Utilizzo di sed e grep / egrep per cercare e sostituire


97

Sto usando egrep -Rseguito da un'espressione regolare contenente circa 10 unioni, quindi come: .jpg | .png | .gifecc. Funziona bene, ora vorrei sostituire tutte le stringhe trovate con.bmp

Stavo pensando a qualcosa di simile

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

quindi il problema qui è come faccio a eseguire un'espressione regolare di unione simile in sede come gli dico di salvare le modifiche al file da cui ha ricevuto l'input.


2
Ho trovato questa domanda mentre cercavo modi per cercare e sostituire su più file in una gerarchia di directory. Per gli altri nella mia situazione, prova rpl .
titaniumdecoy

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

Risposte:


183

Usa questo comando:

egrep -lRZ "\.jpg|\.png|\.gif" . \
    | xargs -0 -l sed -i -e 's/\.jpg\|\.gif\|\.png/.bmp/g'
  • egrep: trova le linee corrispondenti utilizzando espressioni regolari estese

    • -l: elenca solo i nomi dei file corrispondenti

    • -R: ricerca ricorsivamente in tutte le directory date

    • -Z: usa \0come separatore di record

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

    • .: avvia la ricerca nella directory corrente

  • xargs: esegue un comando con lo stdin come argomento

    • -0: usa \0come separatore di record. Questo è importante per abbinare il -Zdi egrepe per evitare di essere ingannati da spazi e nuove righe nei nomi dei file di input.

    • -l: usa una riga per comando come parametro

  • sed: La s tream ed itor

    • -i: sostituisce il file di input con l'output senza fare un backup

    • -e: usa il seguente argomento come espressione

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


funziona tutto tranne il | nella parte sed. Non capisco perché, dato che ha senso ... la parte -l di xargs mi dava degli errori, quindi l'ho tolto, potrebbe essere correlato?
Ori

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

@titanumdecoy: non sono stato in grado di riprodurre questo comportamento. quale versione di sed stavi utilizzando e su quale sistema operativo utilizzi?
David Schmitt

1
@DavidSchmitt: probabilmente vuoi usarlo sed -rper espressioni regolari estese. A quel punto, il modello corrisponderà a ciò che è usato in egrep e potresti volerlo inserire in una variabile per il riutilizzo.
bukzor

questo comando mi ha fatto risparmiare ore di lavoro copiando i file di intestazione dalla mia app per la libreria che ho creato. Questo è fantastico :) Ecco il comando che ho usato egrep -lRZ "\ .h $". | xargs -0 tar -cvf headers.tar | (cp headers.tar headers; cd header; tar xf headers.tar;)
The Lazy Coder

11

Onestamente, per quanto amo sed per i compiti appropriati, questo è sicuramente un compito per perl --èveramente più potente per questo tipo di battute, specialmente per "riscriverlo da dove proviene" (lo -iswitch di perl lo fa per te, e facoltativamente ti consente anche di mantenere la vecchia versione in giro, ad esempio con un .bak aggiunto, usa -i.bakinvece).

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

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


6
sed usa -i, proprio come perl.
Stobor

@ Stobor - Giuro di aver avuto problemi in cui l'operazione perl quando ho alimentato la stringa di sostituzione regex ha fatto esattamente quello che volevo, a differenza di sed, anche se ho dato l'opzione regex a sed.. Penso di aver dimenticato alcuni flag a sed o aveva dei limiti.
meder omuraliev

10

Un altro modo per farlo

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

Qualche aiuto per quanto riguarda il comando precedente

La ricerca farà la ricerca per te nella directory corrente indicata da .

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

-exec eseguire

sed editor di stream

-i ignora maiuscole e minuscole

s è per sostituto

/4.6.0.../ Stringa da cercare

/5.0.0.../ Stringa da sostituire


forse non così potente - ma questo è molto più facile da capire per me rispetto alla risposta accettata
icc97

5

Non sono riuscito a far funzionare nessuno dei comandi su questa pagina: la soluzione sed ha aggiunto una nuova riga alla fine di tutti i file che ha elaborato e la soluzione perl non è stata in grado di accettare abbastanza argomenti da find. Ho trovato questa soluzione che funziona perfettamente:

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

Questo ripeterà l'albero della directory corrente e lo sostituirà search_regexcon replacement_stringqualsiasi file che termina con .ho .m.

Ho anche usato rpl per questo scopo in passato.


0

prova qualcosa usando 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 andare.


3
xargs è decisamente più appropriato qui.
Nathan Fellman

1
e l'utilizzo del |while read ipattern consentirebbe lo streaming ed eviterebbe le restrizioni di lunghezza quando i risultati di egrep diventano troppo lunghi
David Schmitt,

0

Il 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 della directory in cui si trovava la maggior parte dei file.

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

spero che abbia aiutato.

AGGIORNA s | foo: / Drive_letter: | foo: / ba / baz / xyz | g


Puoi usare altri delimitatori per il comando sed, e così facendo i nomi dei percorsi sono molto più belli:sed 's|foo:/Drive_letter:|foo:/ba/baz/xyz|g'
Kevin
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.