Domanda

Sto cercando di cercare e sostituire una stringa in tutti i file corrispondenti a grep su una macchina Linux. Ho alcune parti di ciò che voglio fare, ma non sono sicuro del modo migliore per metterle insieme.

grep -n 'foo' * mi darà l'output nel modulo:

[filename]:[line number]:[text]

Per ogni file restituito da grep, vorrei sostituire " foo " con " bar " e riscrivi il risultato nel file. C'è un buon modo per farlo? Forse una pipeline di fantasia?

È stato utile?

Soluzione

Intendi cercare e sostituire una stringa in tutti i file corrispondenti a grep?

perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`

Modifica

Dal momento che questa sembra essere una domanda abbastanza popolare pensata che aggiornerei.

Oggi uso principalmente ack-grep poiché è più intuitivo. Quindi il comando sopra sarebbe:

perl -p -i -e 's/old/new/g' `ack -l searchpattern`

Per gestire gli spazi bianchi nei nomi dei file è possibile eseguire:

ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

puoi fare di più con <=>. Supponi di voler limitare la ricerca solo ai file HTML:

ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

E se lo spazio bianco non è un problema è anche più breve:

perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files

Altri suggerimenti

Questo sembra essere quello che vuoi, in base all'esempio che hai dato:

sed -i 's/foo/bar/g' *

Non è ricorsivo (non scenderà nelle sottodirectory). Per una buona soluzione che sostituisce i file selezionati in un albero, uso find:

find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;

Il * .html è l'espressione che i file devono corrispondere, il .bak dopo il -i crea una copia del file originale , con un'estensione .bak (può essere qualsiasi estensione che ti piace) e il g alla fine dell'espressione sed dice a sed di sostituire più copie su una riga (anziché solo la prima). Il -print da trovare è una comodità per mostrare quali file sono stati abbinati. Tutto questo dipende dalle versioni esatte di questi strumenti sul tuo sistema.

Se il tuo sed (1) ha un'opzione -i , allora usalo in questo modo:

for i in *; do
  sed -i 's/foo/bar/' $i
done

In caso contrario, ci sono diversi modi per variare in base alla lingua con cui vuoi giocare:

ruby -i.bak -pe 'sub(%r{foo}, 'bar')' *
perl -pi.bak -e 's/foo/bar/' *

Mi piace e ho usato la soluzione di cui sopra o una ricerca a livello di sistema e la sostituzione tra migliaia di file:

find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;

Presumo con '* .htm?' anziché .html cerca e trova file .htm e .html simili.

Sostituisco .bak con tilde (~) utilizzata più a livello di sistema per semplificare la pulizia dei file di backup.

Funziona usando grep senza bisogno di usare perl o find.

grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @

trova. -type f -print0 | xargs -0 < sed / perl / ruby ??cmd > elaborerà contemporaneamente più nomi di file contenuti nello spazio caricando un interprete per batch. Molto più veloce.

La risposta già fornita sull'uso di trova e sed

find -name '* .html' -print -exec sed -i.bak 's / foo / bar / g' {} \;

è probabilmente la risposta standard. Oppure potresti usare perl -pi -e s / foo / bar / g ' invece del comando sed .

Per gli usi più rapidi, potresti trovare il comando rpl più facile da ricordare. Ecco la sostituzione (foo - > bar), ricorsivamente su tutti i file nella directory corrente:

rpl -R foo bar.

Non è disponibile per impostazione predefinita sulla maggior parte delle distribuzioni Linux ma è veloce da installare ( apt-get install rpl o simile).

Tuttavia, per i lavori più difficili che comportano espressioni regolari e sostituzione sostitutiva, o rinominazioni di file e ricerca e sostituzione, lo strumento più generale e potente di cui sono a conoscenza è repren , un piccolo script Python che ho scritto qualche tempo fa per alcuni compiti di rinominazione e refactoring più spinosi. Le ragioni che potresti preferire sono:

  • Supporta la ridenominazione dei file e la ricerca e sostituzione dei contenuti dei file (incluso lo spostamento dei file tra le directory e la creazione di nuove directory principali).
  • Vedi le modifiche prima di impegnarti a eseguire la ricerca e sostituire.
  • Supporta espressioni regolari con modalità di sostituzione di ritorno, parole intere, senza distinzione tra maiuscole e minuscole e preservazione delle maiuscole (sostituisci foo - > bar, Foo - > Bar, FOO - > BAR).
  • Funziona con sostituzioni multiple, inclusi swap (foo - > bar and bar - > foo) o insiemi di sostituzioni non uniche (foo - > bar, f - > x).

Controlla il README per esempi.

Questo è in realtà più facile di quanto sembri.

grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
  • grep ricorre attraverso il tuo albero (-R) e stampa solo il nome del file (-l), iniziando dalla directory corrente (./)
  • che viene reindirizzato a xargs, che li elabora uno alla volta (-n 1) e usa% come segnaposto (-I%) in un comando shell (sh -c)
  • nel comando shell, prima viene stampato il nome del file (ls%;)
  • quindi sed esegue un'operazione in linea (-i), una sostituzione ('s /') di foo con bar (foo / bar), globalmente (/ g) sul file (di nuovo, rappresentato da%)

Facile peasy. Se hai una buona conoscenza di find, grep, xargs, sed e awk, quasi nulla è impossibile quando si tratta di manipolare i file di testo in bash :)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top