开发者

How to replace string in files and file and folder names recursively with PowerShell?

With PowerShell (although other suggestions are welcome), how does one recursively loop a directory/folder and

  1. replace text A with B in all files,
  2. rename all files so that A is replac开发者_运维知识库ed by B, and last
  3. rename all folders also so that A is replaced by B?


With a few requirements refinements, I ended up with this script:

$match = "MyAssembly" 
$replacement = Read-Host "Please enter a solution name"

$files = Get-ChildItem $(get-location) -filter *MyAssembly* -Recurse

$files |
    Sort-Object -Descending -Property { $_.FullName } |
    Rename-Item -newname { $_.name -replace $match, $replacement } -force



$files = Get-ChildItem $(get-location) -include *.cs, *.csproj, *.sln -Recurse 

foreach($file in $files) 
{ 
    ((Get-Content $file.fullname) -creplace $match, $replacement) | set-content $file.fullname 
}

read-host -prompt "Done! Press any key to close."


I would go with something like this:

Get-ChildItem $directory -Recurse |
    Sort-Object -Descending -Property { $_.FullName } |
    ForEach-Object {
        if (!$_.PsIsContainer) {
            ($_|Get-Content) -replace 'A', 'B' | Set-Content $_.FullName
        }
        $_
    } |
    Rename-Item { $_.name -replace 'A', 'B' }

The Sort-Object is there to ensure that first children (subdirs, files) are listed and then directories after them. (12345)


Untested, but should give you a starting point:

$a = 'A';
$b = 'B';
$all = ls -recurse;
$files = = $all | where{ !$_.PSIsContainer );
$files | %{ 
   $c = ( $_ | get-itemcontent -replace $a,$b ); 
   $c | out-file $_;
}
$all | rename-item -newname ( $_.Name -replace $a,$b );


Untested, may be I'm more lucky ;-)

$hello = 'hello'
$world = 'world'

$files = ls -recurse | ? {-not $_.PSIsContainer} 

foearch ($file in $files) {
  gc -path $file | % {$_ -replace $hello, $world} | Set-Content $file
  ri -newname ($file.name -replace $hello, $world)
}

ls -recurse | ? {$_.PSIsContainer} | ri -newname ($_.name -replace $hello, $world)

To use the same recursion:

$hello = 'hello'
$world = 'world'

$everything = ls -recurse 

foearch ($thing in $everything) {
  if ($thing.PSIsContainer -ne $true) {
     gc -path $thing | % {$_ -replace $hello, $world} | Set-Content $thing
  }
  ri -newname ($thing.name -replace $hello, $world)
}


I needed this for myself and below slightly better version of the script.

I added followings:

  1. Support for verbose parameter so you can actually see what changes script has made.
  2. Ability to specify folders so you can limit changes.
  3. Adding bower.json, txt and md in to include extensions.
  4. Search and replace content first, do rename later.
  5. Do not replace content if search string is not found (this avoids unnecessary change in modified date).
[CmdletBinding(SupportsShouldProcess=$true)]
Param()

$match = "MyProject" 
$replacement = Read-Host "Please enter project name"

$searchFolders = @("MyProject.JS", "MyProject.WebApi", ".")
$extensions = @("*.cs", "*.csproj", "*.sln", "bower.json", "*.txt", "*.md")
foreach($searchFolderRelative in $searchFolders)
{
    $searchFolder = join-path (get-location) $searchFolderRelative
    Write-Verbose "Folder: $searchFolder"

    $recurse = $searchFolderRelative -ne "."

    if (test-path $searchFolder)
    {
        $files = Get-ChildItem (join-path $searchFolder "*") -file -include $extensions  -Recurse:$recurse |
                    Where-Object {Select-String -Path $_.FullName $match -SimpleMatch -Quiet}

        foreach($file in $files) 
        { 
            Write-Verbose "Replaced $match in $file"
            ((Get-Content $file.fullname) -creplace $match, $replacement) | set-content $file.fullname 
        }

        $files = Get-ChildItem $searchFolder -filter *$match* -Recurse:$recurse

        $files |
            Sort-Object -Descending -Property { $_.FullName } |
            % {
                Write-Verbose "Renamed $_"
                $newName = $_.name -replace $match, $replacement
                Rename-Item $_.FullName -newname $newName -force
            }       
    }
    else
    {
        Write-Warning "Path not found: $searchFolder"
    }
}

Note that one change from the answer is that above recurses folder only in specified folders, not in root. If you don't want that then just set $recurse = true.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜