Ответ 1
Вот первая попытка на моей голове.
$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
(Get-Content $file.PSPath) |
Foreach-Object { $_ -replace "Dev", "Demo" } |
Set-Content $file.PSPath
}
У меня есть несколько файлов конфигурации на 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 вы можете легко выполнить это. Я нашел примеры find/replace, но я надеялся на способ, который пересечет все папки в моем каталоге C:\Projects и найдет любые файлы, которые заканчиваются расширением .config. Когда он находит один, я хочу, чтобы он заменил мои строковые значения.
Любые хорошие ресурсы, чтобы узнать, как это сделать или какие-либо гуру PowerShell, которые могут предложить некоторое понимание?
Вот первая попытка на моей голове.
$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
(Get-Content $file.PSPath) |
Foreach-Object { $_ -replace "Dev", "Demo" } |
Set-Content $file.PSPath
}
PowerShell - хороший выбор;) Очень просто перечислить файлы в данном каталоге, прочитать их и обработать.
script может выглядеть так:
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\" Таким образом, вы не уничтожаете последние данные datetime последних обновлений, где строка не была найдена:
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 $_ }
}
Я написал небольшую вспомогательную функцию для замены текста в файле:
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'
}
Я нашел комментарий @Artyom полезным, но, к сожалению, он не отправил ответ.
Это короткая версия, на мой взгляд, лучшей версии принятого ответа;
ls *.config -rec | %{$f=$_; (gc $f.PSPath) | %{$_ -replace "Dev", "Demo"} | sc $f.PSPath}
При выполнении рекурсивной замены необходимо указать путь и имя файла:
Get-ChildItem -Recurse | ForEach { (Get-Content $_.PSPath |
ForEach {$ -creplace "old", "new"}) | Set-Content $_.PSPath }
Этот wil заменит все "старые" на "новые" с учетом регистра во всех файлах ваших папок вашего текущего каталога.