2009-07-23 16 views
91

Sto usando egrep -R seguita da un'espressione regolare contenente circa 10 sindacati, così come: .jpg | .png | .gif ecc Questo funziona bene, ora vorrei sostituire tutte le stringhe trovate con .bmpUsando sed e grep per cercare e sostituire

stavo pensando a qualcosa di simile

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

in modo che il problema qui è come faccio a fare una simile unione espressione regolare in sed e come faccio a dire che per salvare le modifiche apportate al file che ha ottenuto l'ingresso da.

+2

Ho trovato questa domanda durante la ricerca di modi per cercare e sostituire in più file in una gerarchia di directory. Per gli altri nella mia situazione, prova [rpl] (http://freshmeat.net/projects/rpl/). – titaniumdecoy

+0

grazie rpl funziona ed è davvero facile da ricordare .. solo rpl old_string new_string target_files. – cesarpachon

risposta

174

Utilizzare questo comando:

egrep -lRZ "\.jpg|\.png|\.gif" . \ 
    | xargs -0 -l sed -i -e 's/\.jpg\|\.gif\|\.png/.bmp/g' 
  • egrep: trovare corrispondenti linee utilizzando esteso regolare espressioni

    • -l: solo elenco delle corrispondenze nomi di file

    • -R: cercare ricorsivamente attraverso tutte le date directory

    • -Z: utilizzare \0 come separatore di record

    • "\.jpg|\.png|\.gif": abbinare una delle stringhe ".jpg", ".gif" o ".png"

    • .: avviare la ricerca nella directory corrente

  • xargs: eseguire un comando con lo stdin come argomento

    • -0: utilizzare \0 come separatore di record. Questo è importante per far corrispondere lo -Z di egrep e per evitare di essere ingannato da spazi e nuove righe nei nomi dei file di input.

    • -l: utilizzare una riga per ogni comando come parametro

  • sed: il s tream ndr itor

    • -i: sostituire il file di input con la uscita senza fare un backup

    • -e: utilizzare il seguente argomento come espressione

    • 's/\.jpg\|\.gif\|\.png/.bmp/g': sostituire tutte le occorrenze delle stringhe ".jpg", ".gif" o ".png" con ".bmp"

+0

funziona tutto eccetto il | nella parte sed Non capisco perché però dal momento che ha senso ... la parte -l di xargs mi dava errori quindi l'ho tolto, potrebbe essere collegato? – Ori

+0

Ho trovato che questo comando aggiunge una nuova riga alla fine di tutti i file che elabora. – titaniumdecoy

+0

@titanumdecoy: non ero in grado di riprodurre questo comportamento. quale versione di sed stai usando e su quale sistema operativo sei? –

11

Onestamente, per quanto mi piaccia sed per i compiti appropriati, questo è sicuramente un compito per perl - è davvero più potente per questo tipo di one-liner, specialmente per "riscriverlo da dove viene" (perl's Lo switch -i lo fa per te e, facoltativamente, ti consente anche di mantenere la versione precedente ad esempio con un .bak aggiunto, usa invece -i.bak.

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

piuttosto che lavorare intricato in sed (se possibile anche lì) o awk ...

+6

usa sed -i, proprio come perl. – Stobor

+0

@Stobor - Giuro che ho avuto problemi in cui l'operazione Perl quando ho alimentato la stringa di regex replacement ha fatto esattamente quello che volevo, a differenza di sed, anche se ho dato l'opzione regex a 'sed' .. Penso che o abbia dimenticato un po ' bandiere a sed o aveva limitazioni. –

0

provare qualcosa di utilizzare un ciclo for

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

non carino, ma dovrebbe fare.

+3

xargs è decisamente più appropriato qui. –

+1

e l'utilizzo del modello '| while read i' abilita lo streaming ed evita restrizioni di lunghezza quando i risultati di egrep diventano troppo lunghi –

5

Non sono riuscito a far funzionare nessuno dei comandi di questa pagina: lo sed solution ha aggiunto una nuova riga alla fine di tutti i file elaborati e lo perl solution non è stato in grado di accettare sufficienti argomenti da trovare. Ho trovato questa soluzione che funziona perfettamente:

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

Ciò ricorsivamente l'albero directory corrente e sostituirla con search_regexreplacement_string in tutti i file che terminano in .h o .m.

Ho utilizzato anche rpl per questo scopo in passato.

9

Un altro modo per fare questo

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

Alcuni aiuto per quanto riguarda il comando precedente

Il ritrovamento farà la scoperta per voi sulla directory corrente indicato dal .

-name il nome del file nel mio caso il suo pom.xml può dare wild card.

-exec eseguire

sed editor di flusso

-i ignorare caso

s è per sostituire

/4.6.0.../ stringa da cercare

/5.0.0.../ stringa da sostituire

+0

forse non così potenti - ma questo è molto più semplice da comprendere rispetto alla risposta accettata – icc97

0

mio caso d'uso era che volevo sostituire foo:/Drive_Letter con foo:/bar/baz/xyz Nel mio caso sono stato in grado di farlo con il seguente codice. Ero nella stessa posizione di directory in cui c'erano molti file.

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

speranza che ha aiutato.

UPDATE s | foo:/Drive_letter: | foo:/BA/baz/xyz | g

+0

Puoi usare altri delimitatori per il comando sed, e così facendo rende i nomi dei percorsi molto più belli: 'sed 's | foo:/Drive_letter: | foo:/ba/baz/xyz | g'' – Kevin