¿Cómo puedo reemplazar cada aparición de una cadena en un archivo con PowerShell?
Usando PowerShell, quiero reemplazar todas las apariciones exactas de [MYID]
en un archivo determinado con MyValue
. ¿Cuál es la forma más sencilla de hacerlo?
Uso (versión V3):
(Get-Content c:\temp\test.txt).Replace('[MYID]', 'MyValue') | Set-Content c:\temp\test.txt
O para V2:
(Get-Content c:\temp\test.txt) -replace '\[MYID\]', 'MyValue' | Set-Content c:\temp\test.txt
Prefiero usar la clase File de .NET y sus métodos estáticos como se ve en el siguiente ejemplo.
$content = [System.IO.File]::ReadAllText("c:\bla.txt").Replace("[MYID]","MyValue")
[System.IO.File]::WriteAllText("c:\bla.txt", $content)
Esto tiene la ventaja de trabajar con una sola cadena en lugar de una matriz de cadenas como con Get-Content . Los métodos también se encargan de la codificación del archivo (UTF-8 BOM , etc.) sin que usted tenga que preocuparse la mayor parte del tiempo.
Además, los métodos no estropean los finales de línea (finales de línea de Unix que podrían usarse) en contraste con un algoritmo que usa Get-Content y pasa a Set-Content .
Entonces, para mí: menos cosas que puedan romperse con el paso de los años.
Una cosa poco conocida cuando se usan clases .NET es que cuando escribe "[System.IO.File]::" en la ventana de PowerShell, puede presionar la Tabtecla para recorrer los métodos allí.
(Get-Content file.txt) |
Foreach-Object {$_ -replace '\[MYID\]','MyValue'} |
Out-File file.txt
(Get-Content file.txt)
Tenga en cuenta que se requiere el paréntesis :
Sin el paréntesis, el contenido se lee, una línea a la vez, y fluye hacia abajo en la tubería hasta que llega a out-file o set-content, que intenta escribir en el mismo archivo, pero ya está abierto por get-content y obtienes un error. El paréntesis hace que la operación de lectura del contenido se realice una vez (abrir, leer y cerrar). Solo entonces, cuando se hayan leído todas las líneas, se canalizarán una a la vez y cuando lleguen al último comando de la canalización se podrán escribir en el archivo. Es lo mismo que $content=content; $contenido | dónde ...
El de arriba solo se ejecuta para "Un archivo", pero también puede ejecutarlo para varios archivos dentro de su carpeta:
Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
(Get-Content $_ | ForEach { $_ -replace '[MYID]', 'MyValue' }) |
Set-Content $_
}