简体   繁体   中英

Powershell to replace string in all files inside a folder

I am trying to run a powershell script, which will replace the occurrence of a string with another string. I want to remove the angular brackets from the include and replace them with double quotes with the header file name only, without the folder path before the Header file name. Example :

#include <a/b/c/def.hpp>
#include <a/b/c/ddd.hpp> 

to

#include "def.hpp"
#include "ddd.hpp"

I have tried this.

(Get-ChildItem -Recurse | Get-Content | Select-String -Pattern "#include <a/b/c/")-replace '#include <a/b/c/(\w+).*/', '#include "'-replace '>','"'

With this, I get the desired result, but I am not able to use the result and replace the existing line in the source file.

Thanks in advance.

I have to query upto 100 files in a folder. Please suggest the best way to do this.

    INPUT 
#include <a0/b/c/d/HeaderFile1.hpp>
#include <a1/b/c/d/HeaderFile2.hpp>
#include <a2/b/c/d/HeaderFile3.hpp>
#include <a3/b/c/d/HeaderFile4.hpp>
#include <a4/b/c/d/HeaderFile5.hpp>
#include <a5/b/c/d/HeaderFile6.hpp>   


OUTPUT
#include "HeaderFile1.hpp"
#include "HeaderFile2.hpp"
#include "HeaderFile3.hpp"
#include "HeaderFile4.hpp"
#include "HeaderFile5.hpp"
#include "HeaderFile6.hpp"

I created some test files containing your samples:

> Select-String file*.cpp -patt 'hpp'

File1.cpp:1:#include <a0/b/c/d/HeaderFile1.hpp>
File2.cpp:1:#include <a1/b/c/d/HeaderFile2.hpp>
File3.cpp:1:#include <a2/b/c/d/HeaderFile3.hpp>
File4.cpp:1:#include <a3/b/c/d/HeaderFile4.hpp>
File5.cpp:1:#include <a4/b/c/d/HeaderFile5.hpp>
File6.cpp:1:#include <a5/b/c/d/HeaderFile6.hpp>

The following script uses a RegEx explained live on RegEx101 and below static.

## Q:\Test\2018\06\09\SO_50777494.ps1
## the following RegEx usees a positive lookbehind and a
## capture group for the filename.

[RegEx]$Search = '(?<=#include ).*\/([^>]+)>'
$Replace = '"$1"'

ForEach ($File in (Get-ChildItem -Path '.\File*.cpp' -Recurse -File)) {
    (Get-Content $File) -Replace $Search,$Replace |
        Set-Content $File
}

Sample output of a Select-String after replace:

> sls file*.cpp -patt 'hpp'

File1.cpp:1:#include "HeaderFile1.hpp"
File2.cpp:1:#include "HeaderFile2.hpp"
File3.cpp:1:#include "HeaderFile3.hpp"
File4.cpp:1:#include "HeaderFile4.hpp"
File5.cpp:1:#include "HeaderFile5.hpp"
File6.cpp:1:#include "HeaderFile6.hpp"

Explanation of the RegEx:

(?<=#include ).*\/([^>]+)>
  Positive Lookbehind (?<=#include )
  Assert that the Regex below matches
  #include matches the characters #include literally 
  .*
    . matches any character (except for line terminators)
    * Quantifier — Matches between zero and unlimited times, 
      as many times as possible, giving back as needed (greedy)
  \/ matches the character / literally (case sensitive)
  1st Capturing Group ([^>]+)
    Match a single character not present in the list below [^>]+
    + Quantifier — Matches between one and unlimited times, 
      as many times as possible, giving back as needed (greedy)
  > matches the character > literally (case sensitive)

You simply need to write the new text back to the file. here is my way of doing it:

Get-ChildItem -Recurse -File | ForEach-Object {

    (Get-Content $_).replace('#include <a/b/c/def.hpp>','#include "def.hpp"') | Set-Content $_
}

Edit:

Now that you have explained your question, it is clear you need to use a regular expression. the one LotPings has posted will work just fine. so using his RegEx the correct answer is:

Get-ChildItem -Recurse -File | ForEach-Object {

    (Get-Content $_)-replace('(?<=#include ).*\/([^>]+)>','"$1"') | Set-Content $_
}

Edit: tested on the examples you provided, if format might be different (deeper path, special characters in path and so on) please test before. And have a backup

Something like this should work:

$items = Get-ChildItem -Recurse
foreach ($i in $items) {
 $newContent = (Get-Content $i) -replace('#include <((\w)+\/)*(\w+\.hpp)>','#include "$3"')
 $newContent | Set-Content $i
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM