2013-03-14 26 views
147

Ho bisogno di cercare ricorsivamente una stringa specificata all'interno di tutti i file e sottodirectory all'interno di una directory e sostituire questa stringa con un'altra stringa.Come grep e sostituire

So che il comando per trovare che potrebbe assomigliare a questo:

grep 'string_to_find' -r ./* 

Ma come posso sostituire ogni istanza di string_to_find con un'altra stringa?

+0

Non credo che grep possa farlo (potrei sbagliarmi). Modi più semplici sarebbero usare sed o perl per fare la sostituzione –

+1

Prova ad usare la sottostringa 'sed -i '/.*. */Replace /'' –

+1

@Eddy_Em Che sostituirà l'intera linea con replace. È necessario utilizzare il raggruppamento per acquisire la parte della linea prima e dopo la sottostringa e quindi inserirla nella riga di sostituzione. 'sed -i 's/\ (. * \) sottostringa \ (. * \)/\ 1replace \ 2 /'' – JStrahl

risposta

1

Di solito non con grep, ma piuttosto con sed -i 's/string_to_find/another_string/g' o perl -i.bak -pe 's/string_to_find/another_string/g'.

102

Ho la risposta.

grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g' 
+11

Questo scansionerebbe i file corrispondenti due volte ... una volta con 'grep' e poi di nuovo con' sed '. Usare il metodo 'find' è più efficiente ma questo metodo che hai menzionato funziona. – cmevoli

+24

Su OS X sarà necessario cambiare 'sed -i 's/str1/str2/g'' in' sed -i "" s/str1/str2/g'' perché funzioni. – jdf

+2

@jdf perché è così? – chishaku

158

Un'altra opzione è quella di utilizzare trova e quindi passare attraverso sed.

find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \; 
+24

Sul terminale OS X 10.10, è richiesta una stringa di estensione corretta per il parametro '-i'. Ad esempio, 'find/path/to/files -type f -exec sed -i" "" s/oldstring/new string/g "{} \;' In ogni caso, fornire una stringa vuota crea comunque un file di backup diverso da quello descritto nel manuale ... – Eonil

+5

Perché ottengo "sed: errore RE: sequenza di byte non valida". E sì, ho aggiunto il '-i" "' per OS X. Funziona diversamente. – taco

+0

Ho avuto il problema della sequenza di byte illegale su macOS 10.12 e questa domanda/risposta ha risolto il mio problema: http://stackoverflow.com/questions/19242275/re-error-illegal-byte-sequence-on-mac-os-x . – abeboparebop

25

Questo funziona meglio per me su OS X:

grep -r -l 'searchtext' . | sort | uniq | xargs perl -e "s/matchtext/replacetext/" -pi 

Fonte: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files

+0

questo è perfetto! funziona anche con ag: 'ag" search "-l -r. | ordinare | uniq | xargs perl -e 's/search/replace' -pi' –

+1

'sort -u' può sostituire' sort | uniq' –

+0

@sebastiankeller Il comando Perl non ha la barra finale, che è un errore di sintassi. – tripleee

0

Un'altra opzione sarebbe quella di utilizzare solo perl con globstar.

L'abilitazione di shopt -s globstar nel proprio .bashrc (o dovunque) consente al modello glob ** di corrispondere ricorsivamente a tutte le sottodirectory e ai file.

Quindi utilizzando perl -pXe 's/SEARCH/REPLACE/g' -i ** in modo ricorsivo sostituire SEARCH con REPLACE.

Il flag -X dice a perl di "disabilitare tutti gli avvisi" - il che significa che non si lamenterà delle directory.

Il globstar permette anche di fare le cose come sed -i 's/SEARCH/REPLACE/g' **/*.ext se si voleva sostituire SEARCH con REPLACE in tutti i file secondari con l'estensione .ext.

+0

* "Un'altra opzione sarebbe usare solo perl con globstar ..." * - Non su macchine Posixy, come Solaris. Ecco perché sono specificamente alla ricerca di 'grep' e' sed'. – jww

19

Si potrebbe anche seguire come questo ..

Esempio

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g' 

Ciò cercare la stringa 'finestre' in tutti i file relativo alla directory corrente e sostituire 'finestre 'con' linux 'per ogni occorrenza della stringa in ogni file.

+2

Il 'grep' è utile solo se ci sono file che non dovrebbero essere modificati.L'esecuzione di 'sed' su tutti i file aggiornerà la data di modifica del file ma lascerà il contenuto invariato se non ci sono corrispondenze. – tripleee

+0

@tripleee: fai attenzione con * ... ma [sed] lascia il contenuto invariato se non ci sono corrispondenze "*. Quando usi' -i', credo che 'sed' cambi il tempo di file di ogni file che tocca, anche anche se il contenuto è invariato, 'sed' converte anche le terminazioni di riga. Non uso' sed' su Windows in un repository Git perché tutti i 'CRLF' sono cambiati in' LF'. – jww

3

Altre soluzioni combinano sintassi regex. Per utilizzare Perl/modelli PCRE per sia ricerca e sostituzione, e di evitare l'elaborazione di tutti i file, questo funziona abbastanza bene:

grep -rlZP 'match1' | xargs -0r perl -pi -e 's/match2/replace/g;' 

dove match1 e match2 sono di solito identiche ma match1 può essere semplificata per rimuovere funzionalità più avanzate che sono rilevanti solo per la sostituzione, ad es catturare gruppi.

Traduzione: grep in modo ricorsivo ed elenca i file corrispondenti, separati da nul per proteggere eventuali caratteri speciali nel nome del file, che corrispondono a questo modello PCRE, quindi reindirizzare quei nomi di file a xarg che si aspetta un elenco nullo-separato, ma non fare qualsiasi cosa se non si ricevono nomi e ottenere da Perl riscrivere ogni file, sostituendo le linee in cui si trovano le corrispondenze.

Aggiungere l'opzione I a grep per ignorare anche i file binari.

+0

Perl stesso è abbastanza capace di ricorsificare un file In effetti, esiste uno strumento ['find2perl'] (https://perldoc.perl.org/5.8.8/find2perl.html) fornito con Perl che fa questo genere di cose senza alcun trucco di' xargs'. – tripleee

+0

@tripleee 'find' non esegue la ricerca nel contenuto del file e il punto è elaborare solo i file corrispondenti senza scrivere un programma Perl. – Walf

-3

trovare & sostituire nel VI modalità di un file La sintassi è la seguente: :% s/WORD-To-Find-HERE/Replace-Word-Qui/g

O :% s/FindMe/replaceme/g

Esempi

Il comando sostitutivo può essere utilizzato secondo le vostre esigenze.