0

I am trying to create a Power Shell script that is replacing one string with another in all folder and sub-folder files also to print all the paths the script went through. So I have written the Bash command but can't convert it to Powershell command

Here is the bash command that is doing the job correctly

find ./ -print -type f -exec sed -i 's/string1/string2/g' {} \;

The closest I found was

ls * -rec | %{ $f=$_; (gc $f.PSPath) | %{ $_ -replace "string1", "string2" } | sc $f.PSPath }

But it looks like is not doing the job the same, plus it is not printing the path

Stefanija
  • 1,388
  • 2
  • 12
  • 25
  • 1
    Please edit the question and explain what the Bash script is supposed to do. Idiomatic Powershell with pipelines and objects is quite different from Bash approach in many cases. – vonPryz Mar 07 '19 at 11:46
  • Setting `$f=$_` doesn't output anything, insert `$f=$_;$f;...` or `foreach ($File in (Get-ChildItem -File -Recurse)){$File.FullName;(Get-Content $File) -replace "string1", "string2" | Set-Content $File }` –  Mar 07 '19 at 12:04

1 Answers1

1

You don't need multiple ForEach-Object loops. For implementing -type f you need to filter for files, though. In PowerShell v3 and newer you'd do that with the parameter -File. In earlier versions you'd have to add a Where-Object {$_.PSIsContainer} to the pipeline.

Something like this should do what you want:

Get-ChildItem -Recurse -File | ForEach-Object {
    (Get-Content $_.FullName) -replace 'string1', 'string2' |
        Set-Content $_.FullName
    $_.FullName
}

or (for short):

ls -r -File | %{(gc $_.FullName) -replace 'string1', 'string2' | sc $_.FullName; $_.FullName}

Note that Set-Content automatically saves the file with ASCII encoding (well, technically it's an ANSI encoding, but let's ignore that since Microsoft has the bad habit of using the two terms synonymous anyway), so you may need to specify a different encoding if you don't want that.

Note also that if you have non-text files you may want to exclude them from processing, since Get-Content and Set-Content do specific things when reading/writing files that are undesirable for binary files (Get-Content without the parameter -Raw or -Encoding Byte splits the input at newlines, Set-Content appends a newline (CR-LF) to the end of each input string before writing them to the output file).

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • `$_ | gc` is even shorter than `gc $_.FullName`. Also, converting FileInfo objects to string gives the `FullName`, so that technically `sc $_` and `gc $_` would be valid. – Tomalak Mar 07 '19 at 12:13
  • 1
    True for `$_ | gc`. But I wanted to retain at least some level of readability. This isn't Perl after all. ;) As for the auto-conversion: that depends on the context unfortunately. In some cases the `Name` property is expanded, and in others the `FullName` property, so using `$_.FullName` is usually the safer approach. – Ansgar Wiechers Mar 07 '19 at 12:16
  • 2
    Yep, that was more of an FYI for the OP. The only gripe I have with the `gc` / `sc` approach is that it silently changes file encodings, which may blow up further down the line in subsequent processing. – Tomalak Mar 07 '19 at 12:20
  • it is weird cuz the command this way changes also the .png files, what is there to be changed? – Stefanija Mar 07 '19 at 12:25
  • As I am noticing it is changing file content with file path ... I am trying the shorter version – Stefanija Mar 07 '19 at 12:34
  • @Merian For more details about how `Set-Content` handles output see [this answer](https://stackoverflow.com/a/42451413/1630171). TL;DR: you'll want to exclude binary files from text file processing. – Ansgar Wiechers Mar 07 '19 at 12:38
  • Nitpicking: the `print all the paths the script went through` part is missing. –  Mar 07 '19 at 12:56
  • 1
    Added (sort of). However, that will only display the paths of the *files*, not those of folders. If they want to re-create the behavior of the `find` commandline *exactly* they'd need to enumerate/print everything (files and folders) and discriminate between files and folders only for the replacement operation. – Ansgar Wiechers Mar 07 '19 at 13:28