Сценарий PowerShell для поиска и замены всех файлов с определенным расширением
у меня есть несколько файлов конфигурации на Windows Server 2008 вложенных как такие:
C:ProjectsProject_1project1.config
C:ProjectsProject_2project2.config
В моей конфигурации, мне нужно сделать строку заменить, как например:
<add key="Environment" value="Dev"/>
будет:
<add key="Environment" value="Demo"/>
Я думал об использовании пакетных сценариев, но не было хорошего способа сделать это, и я слышал, что с помощью сценариев PowerShell вы можете легко выполнить это. Я нашел примеры поиска / замены, но я надеялся на способ, который будет пересекать все папки внутри мой C:Projects каталог и найти любые файлы, которые заканчиваются на '.расширение конфигурации. Когда он находит один, я хочу, чтобы он заменил мои строковые значения.
любые хорошие ресурсы, чтобы узнать, как это сделать, или любые гуру PowerShell, которые могут предложить некоторое представление?
8 ответов:
вот первая попытка на макушке моей головы.
$configFiles = Get-ChildItem . *.config -rec foreach ($file in $configFiles) { (Get-Content $file.PSPath) | Foreach-Object { $_ -replace "Dev", "Demo" } | Set-Content $file.PSPath }
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
.
этот подход хорошо работает:
gci C:\Projects *.config -recurse | ForEach { (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_ }
- измените "старый" и "новый" на их соответствующие значения (или используйте переменные).
- не забудьте скобки -- без которых вы получите ошибку доступа.
Я бы пошел с 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) }
этот пример 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 $_ } }
Я нашел комментарий @Artyom полезно, но к сожалению он не отвечал.
Это короткая версия, на мой взгляд лучшая версия принятого ответа;
ls *.config -rec | %{$f=$_; (gc $f.PSPath) | %{$_ -replace "Dev", "Demo"} | sc $f.PSPath}
Я написал небольшую вспомогательную функцию для замены текста в файле:
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' }