75

I have a simple textfile and I need a powershell script to replace some parts of the file content.

My current script is the following:

$content = Get-Content -path "Input.json"

$content -Replace '"(\d+),(\d{1,})"', '$1.$2' |  Out-File "output.json"

Is it possible to write it in one line without the content variable, like this?

Get-Content -path "Input.json" | ??? -Replace '"(\d+),(\d{1,})"', '$1.$2' |  Out-File "output.json"

I don't know how I can use the output of the first get-content commandlet in the second command without the $content variable? Is there an automatic powershell variable

Is it possible to do more replacements than one in a pipeline.

Get-Content -path "Input.json" | ??? -Replace '"(\d+),(\d{1,})"', '$1.$2' | ??? -Replace 'second regex', 'second replacement' |  Out-File "output.json"

2 Answers 2

115

Yes, you can do that in one line and don't even need a pipeline, as -replace works on arrays like you would expect it to do (and you can chain the operator):

(Get-Content Input.json) `
    -replace '"(\d+),(\d{1,})"', '$1.$2' `
    -replace 'second regex', 'second replacement' |
  Out-File output.json

(Line breaks added for readability.)

The parentheses around the Get-Content call are necessary to prevent the -replace operator being interpreted as an argument to Get-Content.

Sign up to request clarification or add additional context in comments.

10 Comments

Although it only works on one-line-at-a-time "`n", "b" -replace('\n', 'a') will return 'a', 'b' . "`n", "b" -replace('\nb', 'a') Will still return "`n", "b"
@TheRedPea: You can do it with all lines at once by using Get-Content -Raw instead. You then get a single string back.
@TheRedPea: Well, you were still correct in that the approach outlined in the answer is unsuitable for certain replacements, namely those that require the regex to look at subsequent lines, because each line in a single string and runs through the -replace individually.
This messes with the encoding of the output file and puts a byte-order mark on the file. I did it like this to get it to output UTF-8 without bom: $tmp = (Get-Content Input.json) -replace '"(\d+),(\d{1,})"', '$1.$2'; [System.IO.File]::WriteAllLines( 'output.json', $tmp) (Perhaps you need full path on the output filename).
Set-Content -Path 'output.json' also works to output text without a byte order mark.
|
16

Is it possible to write it in one line without the content variable, like this?

Yes: use ForEach-Object (or its alias %) and then $_ to reference the object on the pipeline:

Get-Content -path "Input.json" | % { $_ -Replace '"(\d+),(\d{1,})"', '$1.$2' } |  Out-File "output.json"

Is it possible to do more replacements than one in a pipeline.

Yes.

  1. As above: just adding more Foreach-Object segments.
  2. As -replace returns the result, they can be chained in a single expression:

    ($_ -replace $a,$b) -replace $c,$d
    

    I suspect the parentheses are not needed, but I think they make it easier to read: clearly more than a few chained operators (especially if the match/replacements are non-trivial) will not be clear.

5 Comments

Your solution works only with the parentheses around the Get-Content command let. (Get-Content -path $inputFile) | % { $_ -Replace '"(\d+),(\d{1,})"', '$1.$2' -Replace '"(\d+)"', '$1' -Replace '_', ''} | Out-File $outputFile
@JanBaer Those parentheses are only needed if $InputFile is the same as $OutputFile.
Have you got any references on why the parentheses makes writing to the input file possible? This was exactly the use case I needed, but I find it non-obvious.
@ChrisFCarroll Because it causes the whole file to be read in first. Otherwise it will be read and processed one line at a time; and will still be open for reading when you come to try and write the first line.
The solution works not, when the input file and output file are the same. Then the file content becomes deleted. When I have a different output file, it works fine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.