С помощью PowerShell, я хочу заменить всех точных вхождений [MYID] в данном файле с
значения MyValue`. Какой самый простой способ сделать это?
Использовать (версия V3):
(Get-Content c:\temp\test.txt).replace('[MYID]', 'MyValue') | Set-Content c:\temp\test.txt
Или для V2:
(Get-Content c:\temp\test.txt) -replace '\[MYID\]', 'MyValue' | Set-Content c:\temp\test.txt
(Get-Content file.txt) |
Foreach-Object {$_ -replace '\[MYID\]','MyValue'} |
Out-File file.txt
Обратите внимание на круглые скобки `(вам-контент file.txt) требуется:
без скобок содержание читать, строка за строкой, и стекает в трубопровод, пока он тянется-файл или набор контента, который пытается писать в тот же файл, но это's уже открыт вам-контент, и вы получите сообщение об ошибке. В скобках операция содержимого чтения проводится один раз (открыть, прочитать и закрыть). Только тогда, когда все строки были прочитаны, они передаются по одному и, когда они достигают последней команды в конвейере они могут быть записаны в файл. Это'ы же, как и $содержание=содержание; $Содержание | где ...
Я предпочитаю использовать файл-класс .NET и его статические методы, как показано в следующем примере.
$content = [System.IO.File]::ReadAllText("c:\bla.txt").Replace("[MYID]","MyValue")
[System.IO.File]::WriteAllText("c:\bla.txt", $content)
Это имеет то преимущество, работая с одну строку, а не строку-массив с получить-Содержание. Способы также позаботиться о кодировке файл (UTF-8 спецификации и т. д.) без необходимости заботиться большую часть времени.
Также методов Дон'т испортить окончаний строк (в Unix окончания строк, которые могут быть использованы) в отличие от алгоритма с помощью Get-Content и трубопроводов по набор содержание.
Так что для меня: меньше вещей, которые могут сломаться на протяжении многих лет.
Малоизвестная вещь при использовании .Классы сетей заключается в том, что когда вы ввели в "[Система.ИО.Файл]::" в окне PowerShell вы можете нажать на <и>в разделе</роз> ключ к шагу через методы.
Один выше работает только для "один файл", но вы также можете запустить несколько файлов в папке:
Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
(Get-Content $_ | ForEach { $_ -replace '[MYID]', 'MyValue' }) |
Set-Content $_
}
Это то, что я использую, но медленно на больших текстовых файлов.
get-content $pathToFile | % { $_ -replace $stringToReplace, $replaceWith } | set-content $pathToFile
Если вы собираетесь заменить строки в больших текстовых файлов и скорость, рассмотреть возможность использования система.ИО.Что streamreader и система.ИО.Модулю записи StreamWriter.
try
{
$reader = [System.IO.StreamReader] $pathToFile
$data = $reader.ReadToEnd()
$reader.close()
}
finally
{
if ($reader -ne $null)
{
$reader.dispose()
}
}
$data = $data -replace $stringToReplace, $replaceWith
try
{
$writer = [System.IO.StreamWriter] $pathToFile
$writer.write($data)
$writer.close()
}
finally
{
if ($writer -ne $null)
{
$writer.dispose()
}
}
(Приведенный выше код не тестировался.)
Вероятно, существует более элегантный способ, чтобы использовать streamreader и StreamWriter для замены текста в документе, но это должно дать вам хорошей отправной точкой.
Кредит на @rominator007
Я завернул его в функцию (потому что вы, возможно, захотите использовать его снова)
function Replace-AllStringsInFile($SearchString,$ReplaceString,$FullPathToFile)
{
$content = [System.IO.File]::ReadAllText("$FullPathToFile").Replace("$SearchString","$ReplaceString")
[System.IO.File]::WriteAllText("$FullPathToFile", $content)
}
Примечание: это не является чувствительным к регистру!!!!!
См. этот пост: https://stackoverflow.com/questions/6275980/string-replace-ignoring-case
Я нашел малоизвестные, но удивительно прохладный способ сделать это из Пайетт'ы в Windows PowerShell в действии. Вы можете ссылаться на файлы, такие как переменные, аналогичные $env:в путь, но вам нужно добавить фигурные скобки.
${c:file.txt} = ${c:file.txt} -replace 'oldvalue','newvalue'
Этот работал для меня, используя текущую рабочую директорию в PowerShell. Вам нужно использовать поле fullName
, и он выиграл't работа в PowerShell версии 5. Мне нужно менять цель .Net версии в файлах все мои csproj файл`.
в
gci -Recurse -Filter *.csproj |
% { (get-content "$($_.FullName)")
.Replace('<TargetFramework>net47</TargetFramework>', '<TargetFramework>net462</TargetFramework>') |
Set-Content "$($_.FullName)"}
Немного старых и разных, как мне нужно изменить некоторые строки В все экземпляры конкретного имени файла.
Кроме того, в точно установленное содержание не возвращаются стабильные результаты, поэтому мне пришлось прибегнуть к из файла
.
Код ниже:
$FileName =''
$OldLine = ''
$NewLine = ''
$Drives = Get-PSDrive -PSProvider FileSystem
foreach ($Drive in $Drives) {
Push-Location $Drive.Root
Get-ChildItem -Filter "$FileName" -Recurse | ForEach {
(Get-Content $_.FullName).Replace($OldLine, $NewLine) | Out-File $_.FullName
}
Pop-Location
}
Это то, что работал лучше для меня на этой версии PowerShell:
основные.Незначительные.Построить.Пересмотр
5.1.16299.98
Небольшая поправка на содержание команды. Если искомая строка не найдена `установить-содержание команды будет пустой (пустой) файл.
Вы можете сначала проверить, если строка, которую вы ищете или нет. Если нет, то ничего не заменит.
If (select-string -path "c:\Windows\System32\drivers\etc\hosts" -pattern "String to look for") `
{(Get-Content c:\Windows\System32\drivers\etc\hosts).replace('String to look for', 'String to replace with') | Set-Content c:\Windows\System32\drivers\etc\hosts}
Else{"Nothing happened"}