Как рекурсивно заменить строку в файлах и именах файлов и папок с помощью PowerShell?

с PowerShell (хотя другие предложения приветствуются), как рекурсивно цикл каталога / папки и

  1. заменить текст A на B во всех файлах,
  2. переименуйте все файлы так, чтобы A был заменен B, и last
  3. переименовать все папки также так, чтобы A был заменен B?

6 ответов


с несколькими уточнениями требований, я закончил с этим скриптом:

$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."

Я бы пошел с что-то вроде этого:

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' }

на Sort-Object должен был убедиться, что первые дети (подкаталоги, файлы) и затем директории после них. (12345)


проверялось, но должно дать вам отправную точку:

$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 );

непроверенный, может быть, мне больше повезет ; -)

$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)

использовать ту же рекурсию:

$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)
}

мне это было нужно для себя и ниже немного лучшей версии скрипта.

я добавил следующее:

  1. поддержка подробного параметра, чтобы вы могли видеть, какие изменения внес скрипт.
  2. возможность указать папки, так что вы можете ограничить изменения.
  3. добавление bower.json, txt и md для включения расширений.
  4. поиск и замена контента во-первых, переименовать позже.
  5. Не заменяйте содержимое, если строка поиска не найдено (это позволяет избежать ненужных изменений в измененной дате).
[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"
    }
}

обратите внимание, что одно изменение от ответа заключается в том, что выше повторяется только папку в указанных папок, не в корень. Если вы этого не хотите, просто установите $recurse = true.


Использовать Notepad++ Если у вас нет этого инструмента - вы упускаете много возможностей, необходимых для манипуляций с файлами.

Он имеет функцию замены, которая позволяет искать в данном каталоге, давать шаблоны для файлов и заменять с помощью regexp, расширенной функции или обычной замены.

мощный инструмент.

Это бесплатно: (http://notepad-plus-plus.org/download/v6.6.9.html)