Скрипт PowerShell для поиска и замены всех файлов с определенным расширением - PullRequest
109 голосов
/ 15 мая 2010

У меня есть несколько файлов конфигурации на Windows Server 2008, вложенных как:

C:\Projects\Project_1\project1.config

C:\Projects\Project_2\project2.config

В моей конфигурации мне нужно заменить строку следующим образом:

<add key="Environment" value="Dev"/>

станет:

<add key="Environment" value="Demo"/>

Я думал об использовании пакетных сценариев, но не было никакого хорошего способа сделать это, и я слышал, что с помощью сценариев PowerShell вы можете легко выполнить это. Я нашел примеры поиска / замены, но я надеялся найти способ, который обойдет все папки в моем каталоге C: \ Projects и найдет любые файлы, которые заканчиваются расширением .config. Когда он находит один, я хочу, чтобы он заменил мои строковые значения.

Какие-нибудь полезные ресурсы, чтобы узнать, как это сделать или любой гуру PowerShell, которые могут предложить некоторое понимание?

Ответы [ 8 ]

156 голосов
/ 15 мая 2010

Вот первая попытка на макушке.

$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
    (Get-Content $file.PSPath) |
    Foreach-Object { $_ -replace "Dev", "Demo" } |
    Set-Content $file.PSPath
}
30 голосов
/ 15 мая 2010

PowerShell - хороший выбор;) Очень легко перечислять файлы в заданном каталоге, читать их и обрабатывать.

Сценарий может выглядеть так:

Get-ChildItem C:\Projects *.config -recurse |
    Foreach-Object {
        $c = ($_ | Get-Content) 
        $c = $c -replace '<add key="Environment" value="Dev"/>','<add key="Environment" value="Demo"/>'
        [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))
    }

Я разделил код на несколько строк, чтобы их можно было прочитать. Обратите внимание, что вы можете использовать Set-Content вместо [IO.File]::WriteAllText, но он добавляет новую строку в конце. С WriteAllText вы можете избежать этого.

В противном случае код может выглядеть следующим образом: $c | Set-Content $_.FullName.

14 голосов
/ 01 октября 2013

Этот подход хорошо работает:

gci C:\Projects *.config -recurse | ForEach {
  (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_ 
}
  • Замените "старый" и "новый" на соответствующие им значения (или используйте переменные).
  • Не забудьте про скобки - без которых вы получите ошибку доступа.
9 голосов
/ 16 мая 2010

Я бы пошел с xml и xpath:

dir C:\Projects\project_*\project*.config -recurse | foreach-object{  
   $wc = [xml](Get-Content $_.fullname)
   $wc.SelectNodes("//add[@key='Environment'][@value='Dev']") | Foreach-Object {$_.value = 'Demo'}  
   $wc.Save($_.fullname)  
}
7 голосов
/ 09 мая 2017

Я нашел комментарий @ Артём полезным, но, к сожалению, он не опубликовал ответ.

Это краткая, на мой взгляд, лучшая версия принятого ответа;

ls *.config -rec | %{$f=$_; (gc $f.PSPath) | %{$_ -replace "Dev", "Demo"} | sc $f.PSPath}
7 голосов
/ 23 мая 2015

Этот пример powershell ищет все экземпляры строки "\ foo \" в папке и ее подпапках, заменяет "\ foo \" на "\ bar \" и НЕ перезаписывает файлы, которые не содержат строку " \ foo \ "Таким образом, вы не уничтожаете файл с последним обновлением отметок даты и времени обновления, где строка не найдена:

Get-ChildItem  -Path C:\YOUR_ROOT_PATH\*.* -recurse 
 | ForEach {If (Get-Content $_.FullName | Select-String -Pattern '\\foo\\') 
           {(Get-Content $_ | ForEach {$_ -replace '\\foo\\', '\bar\'}) | Set-Content $_ }
           }
5 голосов
/ 26 мая 2016

Я написал небольшую вспомогательную функцию для замены текста в файле:

function Replace-TextInFile
{
    Param(
        [string]$FilePath,
        [string]$Pattern,
        [string]$Replacement
    )

    [System.IO.File]::WriteAllText(
        $FilePath,
        ([System.IO.File]::ReadAllText($FilePath) -replace $Pattern, $Replacement)
    )
}

Пример:

Get-ChildItem . *.config -rec | ForEach-Object { 
    Replace-TextInFile -FilePath $_ -Pattern 'old' -Replacement 'new' 
}
4 голосов
/ 25 июля 2017

При выполнении рекурсивной замены необходимо указать путь и имя файла:

Get-ChildItem -Recurse | ForEach {  (Get-Content $_.PSPath | 
ForEach {$ -creplace "old", "new"}) | Set-Content $_.PSPath }

Это заменит все «старые» на «новые» с учетом регистра во всех файлах ваших папок в текущей папке.каталог.

...