igbgotiz
igbgotiz

Reputation: 942

Powershell: Replace last occurence of a line in a file

Suppose we have a file foo.txt:

abc
abc
abc

And I want to turn it into:

abc
abc
HelloWorld

This command should work:

(gc foo.txt -Raw) -replace '(.*)abc', '$1HelloWorld' | Out-File foo.txt

Because I'm using -Raw switch, which reads the entire file instead of one line at a time. Then, the greedy pattern (.*) should match everything up to the last "abc" and replace it with "HelloWorld".

But it doesn't work. All 3 occurences of "abc" are replaced with "HelloWorld", as if "-replace" was processing the file one line at a time, despite the -Raw switch.

Why?

Upvotes: 1

Views: 1529

Answers (3)

JamesQMurphy
JamesQMurphy

Reputation: 4428

You have to include the single line mode modifier (?s) like so:

(gc foo.txt -Raw) -replace '(?s)(.*)abc', '$1HelloWorld' | Out-File foo.txt

Without it, the . will not match carriage returns and line feeds.

Upvotes: 2

Saleem
Saleem

Reputation: 8978

I'm breaking PS to multiple lines for sake of simplicity. I'm replacing sed with TEMPOR

Try:

$rx = '(?is)(.*)sed(.*)'           ## Search for last occurance of sed.
$replacement = '$1TEMPOR$2'        ## Replace sed with TEMPOR
(Get-Content -Path d:\data.txt -Raw) -ireplace $rx, $replacement | Out-File d:\test.txt

Content of data.txt:

A nulla odio aptent metus, 
mattis mattis elementum iaculis, 
malesuada proin vestibulum suspendisse pellentesque wisi. 
Faucibus turpis a ac. Wisi eros sed sit nec sed, 
sed et fringilla vulputate mattis pretium, 
rutrum vitae vitae euismod erat eu. 
Ac feugiat sed elit, pellentesque amet dis, 
non lorem vero rutrum, vel eu sodales orci a, 
vestibulum ante consectetur. 
Dui wisi massa a ut seddictumst, 
ultricies sed metus, 
orci urna amet mauris nibh, leo nec fusce.

Output of test.txt:

A nulla odio aptent metus, 
mattis mattis elementum iaculis, 
malesuada proin vestibulum suspendisse pellentesque wisi. 
Faucibus turpis a ac. Wisi eros sed sit nec sed, 
sed et fringilla vulputate mattis pretium, 
rutrum vitae vitae euismod erat eu. 
Ac feugiat sed elit, pellentesque amet dis, 
non lorem vero rutrum, vel eu sodales orci a, 
vestibulum ante consectetur. 
Dui wisi massa a ut seddictumst, 
ultricies TEMPOR metus, 
orci urna amet mauris nibh, leo nec fusce.

Hopefully it answers your question.

Upvotes: 0

Ariel Livshits
Ariel Livshits

Reputation: 591

This is the right way to do it as you tried:

(Get-Content -Path C:\temp\test.txt -Raw) -replace '(.*)abc$', 'HelloWorld' | Out-File C:\temp\test.txt

And this is another way to do it:

$lines = Get-Content -Path C:\temp\test.txt
$last = $lines.Length - 1
$lines[$last] = "testtest"
Set-Content -Path C:\temp\test.txt -Value $lines

Upvotes: -1

Related Questions