2

I want to do this

  • read the file
  • go through each line
  • if the line matches the pattern, do some changes with that line
  • save the content to another file

For now I use this script:

$file = [System.IO.File]::ReadLines("C:\path\to\some\file1.txt")
$output = "C:\path\to\some\file2.txt"

ForEach ($line in $file) {
    if($line -match 'some_regex_expression') {
        $line = $line.replace("some","great")
    }
    Out-File -append -filepath $output -inputobject $line
}

As you can see, here I write line by line. Is it possible to write the whole file at once ?

Good example is provided here :

(Get-Content c:\temp\test.txt) -replace '\[MYID\]', 'MyValue' | Set-Content c:\temp\test.txt

But my problem is that I have additional IF statement...

So, what could I do to improve my script ?

  • The requirement "*As you can see, here I write line by line. Is it possible to write the whole file at once ?*" is confusing as `Set-Content` doesn't write the *whole file at once* either. In stead, it uses the pipeline: while still reading the source file it is already replacing the content in each line and writing it to the output file... I quess you just looking for a one line command, or? – iRon Jul 18 '18 at 12:43

3 Answers3

2

You could do it like that:

Get-Content -Path "C:\path\to\some\file1.txt" | foreach {
    if($_ -match 'some_regex_expression') {
        $_.replace("some","great")
    }
    else {
        $_
    }
} | Out-File -filepath "C:\path\to\some\file2.txt"

Get-Content reads a file line by line (array of strings) by default so you can just pipe it into a foreach loop, process each line within the loop and pipe the whole output into your file2.txt.

TobyU
  • 3,718
  • 2
  • 21
  • 32
  • Hi, Welcome to Stack Overflow and thank you for your first answer. To make the answer more useful to other people, it is best practice to make your answer more detailed for instance to annotate your answer with text that explains why it addresses the OP's original question. – Spangen Jul 18 '18 at 10:23
0

In this case Arrays or Array List(lists are better for large arrays) would be the most elegant solution. Simply add strings in array until ForEach loop ends. After that just flush array to a file.

This is Array List example

$file = [System.IO.File]::ReadLines("C:\path\to\some\file1.txt")
$output = "C:\path\to\some\file2.txt"
$outputData = New-Object System.Collections.ArrayList

ForEach ($line in $file) {
    if($line -match 'some_regex_expression') {
        $line = $line.replace("some","great")
    }
    $outputData.Add($line)
}
$outputData |Out-File $output
V3ntr1s
  • 65
  • 4
0

I think the if statement can be avoided in a lot of cases by using regular expression groups (e.g. (.*) and placeholders (e.g. $1, $2 etc.).
As in your example:

(Get-Content .\File1.txt) -Replace 'some(_regex_expression)', 'great$1' | Set-Content .\File2.txt

And for the good example" where [MYID\] might be somewhere inline:

(Get-Content c:\temp\test.txt) -Replace '^(.*)\[MYID\](.*)$', '$1MyValue$2' | Set-Content c:\temp\test.txt

(see also How to replace first and last part of each line with powershell)

iRon
  • 20,463
  • 10
  • 53
  • 79