Menggunakan PowerShell, saya ingin mengganti semua pasti kejadian [MYID]
dalam suatu file dengan MyValue
. Apa adalah cara termudah untuk melakukannya?
Menggunakan (V3):
(Get-Content c:\temp\test.txt).replace('[MYID]', 'MyValue') | Set-Content c:\temp\test.txt
Atau untuk 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
Perhatikan tanda kurung di sekitar (Get-Konten file.txt)
diperlukan:
Tanpa tanda petik konten yang baca, satu baris pada satu waktu, dan mengalir ke pipa hingga mencapai keluar-file atau set-konten, yang mencoba untuk menulis ke file yang sama, tapi itu's sudah terbuka dengan mendapatkan konten dan anda mendapatkan error. Kurung menyebabkan operasi dari isi bacaan yang akan dilakukan setelah (buka, baca dan dekat). Hanya kemudian ketika semua baris telah membaca, mereka disalurkan pada satu waktu dan ketika mereka mencapai perintah terakhir dalam pipa mereka dapat menulis ke file. It's sama dengan $isi=isi; $content | mana ...
Saya lebih suka menggunakan File-kelas .NET dan metode statis seperti yang terlihat dalam contoh berikut.
$content = [System.IO.File]::ReadAllText("c:\bla.txt").Replace("[MYID]","MyValue")
[System.IO.File]::WriteAllText("c:\bla.txt", $content)
Ini memiliki keuntungan dari bekerja dengan String tunggal bukan String-array dengan Get-Isi. Metode yang juga mengurus encoding file (UTF-8 BOM, dll.) tanpa anda harus mengurus sebagian besar waktu.
Juga metode-metode yang don't mengacaukan akhir baris (Unix akhir baris yang dapat digunakan) berbeda dengan algoritma menggunakan Mendapatkan Konten dan perpipaan melalui Set-Isi.
Jadi bagi saya: Sedikit hal-hal yang bisa merusak selama bertahun-tahun.
Sedikit diketahui hal ketika menggunakan .NET kelas adalah bahwa ketika anda mengetik di "[Sistem.IO.File]::" di jendela PowerShell anda dapat menekan Tab kunci untuk langkah melalui metode-metode yang ada.
Salah satu di atas hanya berjalan untuk "Satu File" saja, tetapi anda juga dapat menjalankan beberapa file dalam folder anda:
Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
(Get-Content $_ | ForEach { $_ -replace '[MYID]', 'MyValue' }) |
Set-Content $_
}
Ini adalah apa yang saya gunakan, tetapi lebih lambat pada file teks besar.
get-content $pathToFile | % { $_ -replace $stringToReplace, $replaceWith } | set-content $pathToFile
Jika anda akan mengganti string dalam file teks besar dan kecepatan adalah kekhawatiran, melihat ke dalam menggunakan Sistem.IO.StreamReader dan Sistem.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()
}
}
(Kode di atas belum diuji.)
Mungkin ada cara yang lebih elegan untuk digunakan StreamReader dan StreamWriter untuk mengganti teks dalam dokumen, tetapi harus memberikan titik awal yang baik.
Kredit untuk @rominator007
Aku membungkusnya menjadi sebuah fungsi (karena anda mungkin ingin menggunakannya lagi)
function Replace-AllStringsInFile($SearchString,$ReplaceString,$FullPathToFile)
{
$content = [System.IO.File]::ReadAllText("$FullPathToFile").Replace("$SearchString","$ReplaceString")
[System.IO.File]::WriteAllText("$FullPathToFile", $content)
}
CATATAN: Ini adalah TIDAK case sensitive!!!!!
Lihat posting ini: https://stackoverflow.com/questions/6275980/string-replace-ignoring-case
Saya menemukan sedikit diketahui tapi luar biasa keren cara untuk melakukannya dari Payette's Windows Powershell dalam Tindakan. Anda dapat referensi file seperti variabel, yang mirip dengan $env:jalan, tapi anda perlu menambahkan kurung kurawal.
${c:file.txt} = ${c:file.txt} -replace 'oldvalue','newvalue'
Ini bekerja untuk saya menggunakan direktori kerja saat ini di PowerShell. Anda perlu menggunakan FullName
property, atau tidak't bekerja di PowerShell versi 5. Saya perlu mengubah target .NET framework versi dalam SEMUA saya CSPROJ
file.
gci -Recurse -Filter *.csproj |
% { (get-content "$($_.FullName)")
.Replace('<TargetFramework>net47</TargetFramework>', '<TargetFramework>net462</TargetFramework>') |
Set-Content "$($_.FullName)"}
Sedikit lama dan berbeda, seperti yang saya butuhkan untuk mengubah garis tertentu dalam semua kasus tertentu nama file.
Juga, Set-Konten
tidak kembali hasil yang konsisten, jadi saya harus resor untuk Keluar-File
.
Kode di bawah ini:
$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
}
Ini adalah apa yang bekerja terbaik bagi saya ini versi PowerShell:
Utama.Kecil.Membangun.Revisi
5.1.16299.98
Koreksi kecil untuk Set-Isi perintah. Jika string dicari tidak ditemukan Untuk Konten
perintah akan blank (kosong) file target.
Anda dapat memverifikasi terlebih dahulu jika string yang anda cari ada atau tidak. Jika tidak itu tidak akan mengganti apa-apa.
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"}