Используя PowerShell, я хочу заменить все точные вхождения [MYID]
в данный файл с помощью MyValue
. Каков самый простой способ сделать это?
Как я могу заменить каждое вхождение String в файл с помощью PowerShell?
Ответ 1
Использование (версия 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
Ответ 2
(Get-Content file.txt) |
Foreach-Object {$_ -replace '\[MYID\]','MyValue'} |
Out-File file.txt
Обратите внимание, что требуются круглые скобки вокруг (Get-Content file.txt)
:
Без круглой скобки содержимое считывается, по одной строке за раз, и течет по конвейеру до тех пор, пока не достигнет файла out-file или set-content, который пытается записать в тот же файл, но он уже открыт с помощью get-content и вы получите сообщение об ошибке. Скобки приводят к тому, что операция чтения содержимого выполняется один раз (открывать, читать и закрывать). Только тогда, когда все строки были прочитаны, они по очереди передаются по каналам, и когда они достигают последней команды в конвейере, они могут быть записаны в файл. Это то же самое, что и $content = content; $content | где...
Ответ 3
Я предпочитаю использовать File-класс .NET и его статические методы, как показано в следующем примере.
$content = [System.IO.File]::ReadAllText("c:\bla.txt").Replace("[MYID]","MyValue")
[System.IO.File]::WriteAllText("c:\bla.txt", $content)
Это имеет преимущество в работе с одной строкой вместо String-массива, как с Get-Content. Методы также заботятся о кодировании файла (UTF-8 спецификация и т.д.), Не заботясь об этом большую часть времени.
Также методы не испортят окончания строк (окончание строк Unix, которые могут быть использованы) в отличие от алгоритма с использованием Get-Content и перехода на Set-Content.
Итак, для меня: Меньше вещей, которые могут сломаться на протяжении многих лет.
Малоизвестная вещь при использовании классов .NET заключается в том, что когда вы ввели "[System.IO.File]::" в окне PowerShell, вы можете нажать клавишу Tab, чтобы пройти через методы там.
Ответ 4
Один выше только работает только для "одного файла", но вы также можете запустить его для нескольких файлов в вашей папке:
Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
(Get-Content $_ | ForEach { $_ -replace '[MYID]', 'MyValue' }) |
Set-Content $_
}
Ответ 5
Вы можете попробовать что-то вроде этого:
$path = "C:\testFile.txt"
$word = "searchword"
$replacement = "ReplacementText"
$text = get-content $path
$newText = $text -replace $word,$replacement
$newText > $path
Ответ 6
Это то, что я использую, но оно медленное в больших текстовых файлах.
get-content $pathToFile | % { $_ -replace $stringToReplace, $replaceWith } | set-content $pathToFile
Если вы собираетесь заменять строки в больших текстовых файлах, и скорость вызывает беспокойство, посмотрите System.IO.StreamReader и System.IO.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 для замены текста в документе, но это должно дать вам хорошую отправную точку.
Ответ 7
Это работало для меня, используя текущий рабочий каталог в PowerShell. Вам нужно использовать свойство FullName
, иначе оно не будет работать в PowerShell версии 5. Мне нужно было изменить целевую версию .NET Framework во ВСЕХ моих файлах CSPROJ
.
gci -Recurse -Filter *.csproj |
% { (get-content "$($_.FullName)")
.Replace('<TargetFramework>net47</TargetFramework>', '<TargetFramework>net462</TargetFramework>') |
Set-Content "$($_.FullName)"}
Ответ 8
Немного старый и другой, так как мне нужно было изменить определенную строку во всех экземплярах определенного имени файла.
Кроме того, Set-Content
не давал согласованных результатов, поэтому мне пришлось прибегнуть к Out-File
.
Код ниже:
$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:
Major.Minor.Build.Revision
5.1.16299.98
Ответ 9
Кредит @rominator007
Я обернул его в функцию (потому что вы можете использовать его снова)
function Replace-AllStringsInFile($SearchString,$ReplaceString,$FullPathToFile)
{
$content = [System.IO.File]::ReadAllText("$FullPathToFile").Replace("$SearchString","$ReplaceString")
[System.IO.File]::WriteAllText("$FullPathToFile", $content)
}
ПРИМЕЧАНИЕ: это НЕ чувствительно к регистру !!!!!
Смотрите этот пост: String.Заменить игнорируя регистр
Ответ 10
Я нашел малоизвестный, но удивительно крутой способ сделать это из Payette Windows Powershell в действии. Вы можете ссылаться на файлы как переменные, похожие на $ env: path, но вам нужно добавить фигурные скобки.
${c:file.txt} = ${c:file.txt} -replace 'oldvalue','newvalue'
Ответ 11
Небольшая коррекция для команды Set-Content. Если искомая строка не найдена, команда Set-Content
пустует (пуст) целевой файл.
Вы можете сначала проверить, существует ли строка, которую вы ищете, или нет. Если нет, это ничего не заменит.
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"}
Ответ 12
После слишком большого поиска я выясню простейшую строку, чтобы сделать это без, изменение кодировки:
Get-Content path/to/file.ext | out-file -encoding ASCII targetFile.ext