Reemplazar cadenas en archivos basados en ciertos criterios de búsqueda es una tarea muy común. Cómo puedo
- reemplazar cadena
fooconbaren todos los archivos en el directorio actual? - hacer lo mismo recursivamente para subdirectorios?
- reemplazar solo si el nombre del archivo coincide con otra cadena?
- reemplazar solo si la cadena se encuentra en un determinado contexto?
- reemplazar si la cadena está en un cierto número de línea?
- reemplazar múltiples cadenas con el mismo reemplazo
- reemplazar múltiples cadenas con diferentes reemplazos
text-processing
awk
sed
perl
terdon
fuente
fuente

Respuestas:
1. Reemplazar todas las ocurrencias de una cadena con otra en todos los archivos en el directorio actual:
Estos son para casos en los que sabe que el directorio contiene solo archivos regulares y que desea procesar todos los archivos no ocultos. Si ese no es el caso, use los enfoques en 2.
Todas las
sedsoluciones en esta respuesta asumen GNUsed. Si usa FreeBSD o OS / X, reemplácelo-icon-i ''. También tenga en cuenta que el uso del-iconmutador con cualquier versión desedtiene ciertas implicaciones de seguridad del sistema de archivos y no es aconsejable en cualquier script que planee distribuir de ninguna manera.Archivos no recursivos en este directorio solamente:
(el
perlque fallará para los nombres de archivo que terminan en|o espacio) ).Archivos regulares y recursivos ( incluidos los ocultos ) en este y todos los subdirectorios
Si está usando zsh:
(puede fallar si la lista es demasiado grande, ver
zargspara evitar).Bash no puede verificar directamente los archivos normales, se necesita un bucle (los paréntesis evitan configurar las opciones globalmente):
Los archivos se seleccionan cuando son archivos reales (-f) y se pueden escribir (-w).
2. Reemplace solo si el nombre del archivo coincide con otra cadena / tiene una extensión específica / es de cierto tipo, etc.
Archivos no recursivos en este directorio solamente:
Archivos regulares y recursivos en este y todos los subdirectorios
Si está utilizando bash (las llaves evitan configurar las opciones globalmente):
Si está usando zsh:
El
--sirve para decirsedque no se darán más banderas en la línea de comando. Esto es útil para proteger contra los nombres de archivos que comienzan con-.Si un archivo es de cierto tipo, por ejemplo, ejecutable (ver
man findmás opciones):zsh:3. Reemplace solo si la cadena se encuentra en un contexto determinado
Reemplace
fooconbarsolo si hay unbazposterior en la misma línea:En
sed, el uso de\( \)guardar lo que está entre paréntesis y luego puede acceder a él con\1. Hay muchas variaciones de este tema, para obtener más información sobre tales expresiones regulares, consulte aquí .Reemplace
fooconbarsolo sifoose encuentra en la columna 3d (campo) del archivo de entrada (suponiendo campos separados por espacios en blanco):(necesita
gawk4.1.0 o más reciente).Para un campo diferente, simplemente use
$NwhereNes el número del campo de interés. Para un separador de campo diferente (:en este ejemplo) use:Otra solución usando
perl:NOTA: tanto el
awkyperlsoluciones afectará espaciado en el archivo (eliminar los espacios en blanco de ataque y salida, y convertir secuencias de espacios en blanco para un carácter de espacio en aquellas líneas que responden). Para un campo diferente, use$F[N-1]dóndeNestá el número de campo que desea y para un separador de campo diferente ($"=":"establece el separador de campo de salida en:):Reemplace
fooconbarsolo en la cuarta línea:4. Operaciones de reemplazo múltiple: reemplace con diferentes cadenas
Puedes combinar
sedcomandos:Tenga en cuenta que el orden es importante (
sed 's/foo/bar/g; s/bar/baz/g'sustituiráfooconbaz).o comandos de Perl
Si tiene una gran cantidad de patrones, es más fácil guardar sus patrones y sus reemplazos en un
sedarchivo de script:O, si tiene demasiados pares de patrones para que lo anterior sea factible, puede leer los pares de patrones de un archivo (dos patrones separados por espacios, $ patrón y $ reemplazo, por línea):
Eso será bastante lento para largas listas de patrones y archivos de datos grandes, por lo que es posible que desee leer los patrones y crear un
sedscript a partir de ellos. Lo siguiente supone que un delimitador <space> separa una lista de pares MATCH <space> REPLACE que ocurren uno por línea en el archivopatterns.txt:El formato anterior es en gran medida arbitrario y, por ejemplo, no permite un <space> en MATCH o REPLACE . Sin embargo, el método es muy general: básicamente, si puede crear una secuencia de salida que se parezca a una
sedsecuencia de comandos, puede generar esa secuencia comosedsecuencia de comandos especificandosedel archivo de secuencia de comandos como-stdin.Puede combinar y concatenar múltiples scripts de manera similar:
Un POSIX
sedconcatenará todos los scripts en uno en el orden en que aparecen en la línea de comandos. Ninguno de estos debe terminar en una línea\nelectrónica.greppuede funcionar de la misma manera:Cuando se trabaja con cadenas fijas como patrones, es una buena práctica escapar de los metacaracteres de expresiones regulares . Puedes hacer esto con bastante facilidad:
5. Operaciones de reemplazo múltiple: reemplaza múltiples patrones con la misma cadena
Reemplace cualquiera de
foo,barobazconfoobaro
fuente
zsh. Por supuesto, agreguezshinformación, pero no hay ninguna razón para eliminar las cosas de bash. Además, sé que usar el shell para el procesamiento de texto no es ideal, pero hay casos en los que es necesario. Edité una versión mejor de mi script original que creará unsedscript en lugar de usar el bucle de shell para analizar. Esto puede ser útil si tiene varios cientos de pares de patrones, por ejemplo.(.)calificador global, por lo que no se puede usar aquí. (también te estás perdiendo algo). El bucle for es incorrecto (falta -r) y significa realizar varias pasadas en los archivos y no agrega ningún beneficio sobre un script sed.--despuéssed -iy antes del comando sustituto?-. Su uso asegura que los comandos funcionarán en archivos con nombres como-foo. Sin él, el-fsería analizado como una opción..gitdirectorio, y realmente estropearán su pago. Es mejor operar dentro / sobre directorios específicos por nombre.Una buena r e pl acement herramienta de Linux es RPL , que fue escrito originalmente para el proyecto Debian, por lo que está disponible con
apt-get install rplen cualquier distro derivada de Debian, y puede ser para los demás, pero por lo demás se puede descargar eltar.gzarchivo en SourgeForge .El ejemplo más simple de uso:
Tenga en cuenta que si la cadena contiene espacios, debe estar entre comillas. De forma predeterminada,
rplse ocupan de las letras mayúsculas pero no de las palabras completas , pero puede cambiar estos valores predeterminados con opciones-i(ignorar mayúsculas y minúsculas) y-w(palabras completas). También puede especificar múltiples archivos :O incluso especifique las extensiones (
-x) para buscar o incluso busque recursivamente (-R) en el directorio:También puede buscar / reemplazar en modo interactivo con
-pla opción (solicitud):El resultado muestra los números de archivos / cadenas reemplazados y el tipo de búsqueda (mayúsculas / minúsculas, palabras completas / parciales), pero puede ser silencioso con la opción
-q( modo silencioso ), o incluso más detallado, enumerando números de línea que contienen coincidencias de cada archivo y directorio con la opción-v( modo detallado ).Otras opciones que vale la pena recordar son
-e(honor e scapes) que permitenregular expressions, por lo que puede buscar también pestañas (\t), nuevas líneas (\n), etc. Incluso puede usar-fpara forzar permisos (por supuesto, solo cuando el usuario tiene permisos de escritura) y-dpara preservar los tiempos de modificación ').Finalmente, si no está seguro de cuál será exactamente, use el
-s( modo de simulación ).fuente
Cómo hacer una búsqueda y reemplazar varios archivos sugiere:
Mis mejores resultados provienen del uso de perl y grep (para asegurar que el archivo tenga la expresión de búsqueda)
fuente
Puede usar Vim en modo Ex:
fuente
Usé esto:
Lista todos los archivos que contienen
old_string.Reemplace la nueva línea en el resultado con espacios (para poder alimentar la lista de archivos
sed.Ejecutar
seden esos archivos para reemplazar la cadena vieja con nueva.Actualización: el resultado anterior fallará en los nombres de archivo que contienen espacios en blanco. En cambio, use:
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'fuente
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'lo hará tratar con nombres de archivos arbitrarios.Desde la perspectiva del usuario, una herramienta Unix agradable y simple que hace el trabajo perfectamente es
qsubst. Por ejemplo,reemplazará
fooconbaren todos mis archivos C. Una buena característica es queqsubsthará un reemplazo de consulta , es decir, me mostrará cada apariciónfooy me preguntará si quiero reemplazarlo o no. [Puede reemplazar incondicionalmente (sin preguntar) con la-goopción, y hay otras opciones, por ejemplo,-wsi solo desea reemplazarfoocuando es una palabra completa.]Cómo conseguirlo:
qsubstfue inventado por der Mouse (de McGill) y publicado en comp.unix.sources 11 (7) en agosto de 1987. Existen versiones actualizadas. Por ejemplo, la versión de NetBSD seqsubst.c,v 1.8 2004/11/01compila y se ejecuta perfectamente en mi Mac.fuente
Necesitaba algo que podría proporcionar una opción de funcionamiento en seco y trabajaría de forma recursiva con un pegote, y después de probar a hacerlo con
awkysedme di por vencido y en su lugar hice en pitón.El script busca recursivamente todos los archivos que coinciden con un patrón global (por ejemplo
--glob="*.html") para una expresión regular y la reemplaza con la expresión regular de reemplazo:Cada opción larga como
--search-regextiene una opción corta correspondiente, es decir-s. Ejecute con-hpara ver todas las opciones.Por ejemplo, esto cambiará todas las fechas de
2017-12-31a31-12-2017:fuente
globstaropción de bash (o el equivalente de su shell) y**globs ofind. Para una carrera en seco, solo usesed. A menos que use la-iopción, no hará ningún cambio. Para uso de respaldosed -i.bak(operl -i .bak); para archivos que no coinciden, usegrep PATTERN file || echo file. ¿Y por qué en el mundo tendrías a Python expandir el globo en lugar de dejar que el shell lo haga? ¿Por qué enscript.py --glob=foo*lugar de soloscript.py foo*?sedyawkbien y no estar dispuesto a invertir tiempo extra en el dominio de ellos, (4) la legibilidad, (5) esta solución también trabajará en sistemas no POSIX (No es que lo necesite, pero alguien más podría hacerlo).ripgrep (nombre del comando
rg) es unagrepherramienta, pero también admite la búsqueda y el reemplazo.rgno admite la opción in situ, por lo que deberá hacerlo usted mismoConsulte la documentación de Rust regex para conocer la sintaxis y las características de las expresiones regulares. El
-Pinterruptor habilitará el sabor PCRE2 .rgadmite Unicode de forma predeterminada.Al igual que
grepla-Fopción, permitirá que las cadenas fijas coincidan, una opción práctica que creo que tambiénseddebería implementarse.Otra opción práctica es la
-Uque permite la coincidencia de líneas múltiplesrgtambién puede manejar archivos de estilo dosOtra ventaja de
rges que es probable que sea más rápido quesedfuente