Korzystając z programu PowerShell, chcę zamienić wszystkie dokładne wystąpienia [MYID]
w danym pliku na MyValue
. Jaki jest najłatwiejszy sposób?
powershell
amator
źródło
źródło
Odpowiedzi:
Użyj (wersja V3):
Lub dla V2:
źródło
Uwaga
(Get-Content file.txt)
: wymagane są nawiasy wokół :źródło
Set-Content
zamiastOut-File
yu powoduje wyświetlenie ostrzeżenia „Proces nie może uzyskać dostępu do pliku„ 123.csv ”, ponieważ jest używany przez inny proces.” .Get-Content
w nawiasie to działa. Czy potrafisz wyjaśnić w odpowiedzi, dlaczego nawias jest konieczny? Chciałbym jeszcze wymienićOut-File
zSet-Content
ponieważ jest bezpieczniejsza; chroni cię przed wymazaniem pliku docelowego, jeśli zapomnisz nawias.Set-Content
zamiastOut-File
jest znacznie lepszym i bezpieczniejszym rozwiązaniem. Przepraszam, muszę przegłosować.Wolę używać klasy File .NET i jej metod statycznych, jak pokazano w poniższym przykładzie.
Ma to tę zaletę, że pracuje z jednym ciągiem zamiast tablicy ciągów, jak w przypadku Get-Content . Metody te zajmują się również kodowaniem pliku (UTF-8 BOM itp.) Bez konieczności zajmowania się przez większość czasu.
Również metody nie psują zakończeń linii (uniksowe zakończenia linii, które mogą być użyte) w przeciwieństwie do algorytmu używającego Get-Content i przesyłającego potokiem do Set-Content .
Więc dla mnie: Mniej rzeczy, które mogłyby się zepsuć na przestrzeni lat.
Mało znaną rzeczą podczas korzystania z klas .NET jest to, że po wpisaniu „[System.IO.File] ::” w oknie programu PowerShell można nacisnąć Tabklawisz, aby przejść przez dostępne tam metody.
źródło
[System.IO.File] | gm
C:\Windows\System32\WindowsPowerShell\v1.0
?Powyższy działa tylko dla „jednego pliku”, ale możesz go również uruchomić dla wielu plików w swoim folderze:
źródło
foreach
Możesz to również zrobić za pomocą wewnętrznegoGet-ChildItem 'C:\folder\file*.xml' -Recurse | ForEach { (Get-Content $_).Replace('[MYID]', 'MyValue') | Set-Content $_ }
foreach
, ponieważ Get-Content robi coś, czego nie możesz oczekiwać ... Zwraca tablicę ciągów, gdzie każdy ciąg jest linią w pliku. Jeśli przeglądasz katalog (i podkatalogi) znajdujące się w innym miejscu niż uruchomiony skrypt, potrzebujesz czegoś takiego:Get-ChildItem $Directory -File -Recurse | ForEach { (Get-Content $_.FullName) | ForEach { $_ -replace '[MYID]', 'MyValue' } | Set-Content $_.FullName }
gdzie$Directory
znajduje się katalog zawierający pliki, które chcesz zmodyfikować.Możesz spróbować czegoś takiego:
źródło
Tego używam, ale jest on powolny w przypadku dużych plików tekstowych.
Jeśli zamierzasz zamieniać ciągi w dużych plikach tekstowych, a problemem jest szybkość, skorzystaj z System.IO.StreamReader i System.IO.StreamWriter .
(Powyższy kod nie został przetestowany).
Prawdopodobnie istnieje bardziej elegancki sposób korzystania z StreamReader i StreamWriter do zamiany tekstu w dokumencie, ale powinno to dać dobry punkt wyjścia.
źródło
Znalazłem mało znany, ale niesamowicie fajny sposób, aby to zrobić w Windows PowerShell Payette w akcji . Możesz odwoływać się do plików takich jak zmienne, podobne do $ env: path, ale musisz dodać nawiasy klamrowe.
źródło
$myFile
?$a = 'file.txt'; invoke-expression "`${c:$a} = `${c:$a} -replace 'oldvalue','newvalue'"
Jeśli chcesz zamienić ciągi w wielu plikach:
Należy zauważyć, że różne zamieszczone tutaj metody mogą być bardzo różne w odniesieniu do czasu potrzebnego do ukończenia. Dla mnie regularnie mam dużą liczbę małych plików. Aby przetestować to, co jest najbardziej wydajne, wyodrębniłem 5,52 GB (5 933 604 999 bajtów) XML w 40 693 oddzielnych plikach i przejrzałem trzy odpowiedzi, które tu znalazłem:
źródło
Kredyt na @ rominator007
Zawinąłem go w funkcję (ponieważ możesz chcieć użyć go ponownie)
UWAGA: W NIE jest rozróżniana wielkość liter !!!!!
Zobacz ten post: String.Replace ignorując wielkość liter
źródło
To działało dla mnie przy użyciu bieżącego katalogu roboczego w PowerShell. Musisz użyć
FullName
właściwości, inaczej nie będzie działać w PowerShell w wersji 5. Musiałem zmienić docelową wersję środowiska .NET we WSZYSTKICH moichCSPROJ
plikach.źródło
Trochę stary i inny, ponieważ musiałem zmienić określoną linię we wszystkich instancjach określonej nazwy pliku.
Ponadto
Set-Content
nie zwracał spójnych wyników, więc musiałem się uciekaćOut-File
.Kod poniżej:
Oto, co działało dla mnie najlepiej w tej wersji programu PowerShell:
źródło
Mała korekta polecenia Set-Content. Jeśli szukany ciąg nie zostanie znaleziony,
Set-Content
polecenie wyczyści (opróżni) plik docelowy.Możesz najpierw sprawdzić, czy szukany ciąg istnieje, czy nie. Jeśli nie, nic nie zastąpi.
źródło
set-content test.txt "hello hello world hello world hello"
I wtedy(get-content .\test.txt).Replace("something", "awesome") | set-content .\test.txt
nie opróżni pliku zgodnie z sugestią w tym.