Script de PowerShell para buscar y reemplazar todos los archivos con una extensión específica
powershell replace string in file (8)
Al hacer un reemplazo recursivo, la ruta y el nombre del archivo deben ser incluidos:
Get-ChildItem -Recurse | ForEach { (Get-Content $_.PSPath |
ForEach {$ -creplace "old", "new"}) | Set-Content $_.PSPath }
Esto reemplazará todos los "viejos" por "nuevos" mayúsculas y minúsculas en todos los archivos de sus carpetas de su directorio actual.
Tengo varios archivos de configuración en Windows Server 2008 anidados así:
C:/Projects/Project_1/project1.config
C:/Projects/Project_2/project2.config
En mi configuración necesito hacer una cadena de reemplazo como tal:
<add key="Environment" value="Dev"/>
se convertirá:
<add key="Environment" value="Demo"/>
Pensé en usar scripts por lotes, pero no había una buena manera de hacerlo, y escuché que con el scripting de PowerShell puedes realizar esto fácilmente. He encontrado ejemplos de find / replace, pero esperaba una forma de atravesar todas las carpetas dentro de mi directorio C: / Projects y encontrar cualquier archivo que termine con la extensión ''.config''. Cuando encuentre uno, quiero que reemplace mis valores de cadena.
¿Algún buen recurso para averiguar cómo hacer esto o cualquier gurú de PowerShell que pueda ofrecer alguna información?
Aquí un primer intento en la parte superior de mi cabeza.
$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
(Get-Content $file.PSPath) |
Foreach-Object { $_ -replace "Dev", "Demo" } |
Set-Content $file.PSPath
}
Este ejemplo de PowerShell busca todas las instancias de la cadena "/ foo /" en una carpeta y sus subcarpetas, reemplaza "/ foo /" por "/ bar /" Y NO REESCRIBE archivos que no contengan la cadena "/ foo /" "De esta forma no se destruye el archivo de la última actualización de sellos de fecha y hora donde no se encontró la cadena:
Get-ChildItem -Path C:/YOUR_ROOT_PATH/*.* -recurse
| ForEach {If (Get-Content $_.FullName | Select-String -Pattern ''//foo//')
{(Get-Content $_ | ForEach {$_ -replace ''//foo//', ''/bar/'}) | Set-Content $_ }
}
Este enfoque funciona bien:
gci C:/Projects *.config -recurse | ForEach {
(Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_
}
- Cambia "viejo" y "nuevo" a sus valores correspondientes (o usa variables).
- No olvide el paréntesis, sin el cual recibirá un error de acceso.
He escrito una pequeña función auxiliar para reemplazar texto en un archivo:
function Replace-TextInFile
{
Param(
[string]$FilePath,
[string]$Pattern,
[string]$Replacement
)
[System.IO.File]::WriteAllText(
$FilePath,
([System.IO.File]::ReadAllText($FilePath) -replace $Pattern, $Replacement)
)
}
Ejemplo:
Get-ChildItem . *.config -rec | ForEach-Object {
Replace-TextInFile -FilePath $_ -Pattern ''old'' -Replacement ''new''
}
Me gustaría ir con xml y xpath:
dir C:/Projects/project_*/project*.config -recurse | foreach-object{
$wc = [xml](Get-Content $_.fullname)
$wc.SelectNodes("//add[@key=''Environment''][@value=''Dev'']") | Foreach-Object {$_.value = ''Demo''}
$wc.Save($_.fullname)
}
PowerShell es una buena opción;) Es muy fácil enumerar archivos en un directorio determinado, leerlos y procesarlos.
El script podría verse así:
Get-ChildItem C:/Projects *.config -recurse |
Foreach-Object {
$c = ($_ | Get-Content)
$c = $c -replace ''<add key="Environment" value="Dev"/>'',''<add key="Environment" value="Demo"/>''
[IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))
}
Divido el código en más líneas para que pueda leerlo. Tenga en cuenta que puede usar Set-Content en lugar de [IO.File]::WriteAllText
, pero agrega una nueva línea al final. Con WriteAllText
puedes evitarlo.
De lo contrario, el código podría verse así: $c | Set-Content $_.FullName
$c | Set-Content $_.FullName
.