2009-07-23 26 views
91

estoy usando egrep -R seguido por una expresión regular que contiene cerca de 10 sindicatos, así como: .jpg | .png | .gif etc. Esto funciona bien, ahora me gustaría reemplazar todas las secuencias encontradas con .bmpusando sed y grep para buscar y reemplazar

estaba pensando en algo así como

egrep -lR "\.jpg|\.png|\.gif" . | sed "s/some_expression/.jpg/" file_it_came_form 

por lo que la cuestión aquí es cómo hago una unión expresión regular similar en sed y cómo lo cuento para guardar los cambios en el archivo que tiene la entrada desde.

+2

me encontré con esta pregunta durante la búsqueda de formas de buscar y reemplazar en varios archivos en una jerarquía de directorios. Para otros en mi situación, pruebe [rpl] (http://freshmeat.net/projects/rpl/). – titaniumdecoy

+0

gracias rpl funciona y es realmente fácil de recordar ... simplemente rpl old_string new_string target_files. – cesarpachon

Respuesta

174

Use este comando:

egrep -lRZ "\.jpg|\.png|\.gif" . \ 
    | xargs -0 -l sed -i -e 's/\.jpg\|\.gif\|\.png/.bmp/g' 
  • egrep: encontrar los correspondientes líneas usando expresiones regulares extendidas

    • -l: única lista de coincidencias nombres de archivo

    • -R: búsqueda de forma recursiva a través de todos los directorios dados

    • -Z: utilizar \0 como separador de registros

    • "\.jpg|\.png|\.gif": Al menos uno de los hilos ".jpg", ".gif" o ".png"

    • .: iniciar la búsqueda en el directorio actual

  • xargs: ejecutar un comando con la entrada estándar como argumento

    • -0: \0 utilizar como separador de registros. Esto es importante para que coincida con el -Z de egrep y para evitar ser engañado por espacios y líneas nuevas en los nombres de archivos de entrada.

    • -l: utilizar una línea por cada comando como parámetro

  • sed: la s TREAM ed itor

    • -i: reemplazar el archivo de entrada con el salida sin hacer una copia de seguridad

    • -e: utilizar el siguiente argumento como expresión

    • 's/\.jpg\|\.gif\|\.png/.bmp/g': sustituir todas las apariciones de las cuerdas ".jpg", ".gif" o ".png" con ".bmp"

+0

funciona todo excepto el | en la parte sed No entiendo por qué, aunque como tiene sentido ... la parte -l de xargs me estaba dando errores así que lo saqué, ¿podría estar relacionado? – Ori

+0

Encontré que este comando agrega una nueva línea al final de todos los archivos que procesa. – titaniumdecoy

+0

@titanumdecoy: No pude reproducir este comportamiento. ¿Qué versión de sed usabas y en qué sistema operativo estás? –

11

Honestamente, como me encanta para las tareas apropiadas, esta es definitivamente una tarea para Perl - es realmente más poderoso para este tipo de frases ingeniosas, especialmente para "escribir de nuevo de dónde viene" (perl's El interruptor -i lo hace por usted, y opcionalmente también le permite mantener la versión anterior alrededor, por ejemplo, con un .bak adjunto, simplemente use -i.bak en su lugar).

perl -i.bak -pe 's/\.jpg|\.png|\.gif/.jpg/ 

lugar de trabajo intrincado en sed (si es posible incluso allí) o awk ...

+6

sed usa -i, al igual que perl. – Stobor

+0

@Stobor - Juro que he tenido problemas en los que la operación perl cuando alimenté la cadena de reemplazo de regex hizo exactamente lo que quería, a diferencia de sed, incluso si le di la opción de expresión regular a 'sed' ... Creo que olvidé alguna banderas a sed o tenía limitaciones. –

0

probar algo utilizando un bucle

for i in `egrep -lR "YOURSEARCH" .` ; do echo $i; sed 's/f/k/' <$i >/tmp/`basename $i`; mv /tmp/`basename $i` $i; done 

no es bonito, pero debería hacer.

+3

xargs es definitivamente más apropiado aquí. –

+1

y utilizando el patrón '| while read i' permitiría la transmisión y evitar restricciones de longitud cuando los resultados de egrep sean demasiado largos –

5

No pude obtener ninguno de los comandos en esta página para que funcionen para mí: el sed solution agregó una nueva línea al final de todos los archivos procesados, y el perl solution no pudo aceptar suficientes argumentos de find. He encontrado esta solución que funciona a la perfección:

find . -type f -name '*.[hm]' -print0 
    | xargs -0 perl -pi -e 's/search_regex/replacement_string/g' 

Esto recursivamente el árbol directorio actual y reemplazarlo con search_regexreplacement_string en los archivos que terminan en .h o .m.

También he usado rpl para este propósito en el pasado.

9

Otra manera de hacer esto

find . -name *.xml -exec sed -i "s/4.6.0-SNAPSHOT/5.0.0-SNAPSHOT/" {} \; 

Algunos ayuda en relación con el comando anterior

El hallazgo hará el hallazgo para usted en el directorio actual indicado por .

-name el nombre de la archivo en mi caso es pom.xml puede dar comodines.

-exec ejecutar

sed editor de flujo

-i ignoran caso

s es para substituto

/4.6.0.../ cadena que se debe buscar

/5.0.0.../ cadena que ser reemplazado

+0

quizás no tan poderoso, pero esto es mucho más fácil de entender que la respuesta aceptada – icc97

0

Mi caso de uso era lo que quería para reemplazar foo:/Drive_Letter con foo:/bar/baz/xyz En mi caso tuve la oportunidad de hacerlo con el siguiente código. Estaba en la misma ubicación de directorio donde había una gran cantidad de archivos.

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g' 

espero que haya ayudado.

ACTUALIZACIÓN s | foo:/LetraUnidad | foo:/BA/baz/xyz | g

+0

Puede usar otros delimitadores para el comando sed, y al hacerlo hace que los nombres de las rutas sean mucho más agradables: 'sed 's | foo:/letra_de_puerto: | foo:/ba/baz/xyz | g'' – Kevin

Cuestiones relacionadas