2013-03-14 13 views
147

Ich muss rekursiv nach einer angegebenen Zeichenfolge in allen Dateien und Unterverzeichnissen innerhalb eines Verzeichnisses suchen und diese Zeichenfolge durch eine andere Zeichenfolge ersetzen.Wie grep und ersetzen

Ich weiß, dass der Befehl es so aussehen finden könnte:

grep 'string_to_find' -r ./* 

Aber wie kann ich jede Instanz string_to_find durch eine andere Zeichenfolge ersetzen?

+0

Ich glaube nicht, Grep kann dies tun (ich könnte falsch liegen). Einfachere Methoden wären die Verwendung von sed oder perl zum Ersetzen –

+1

Versuchen Sie 'sed -i 's /.* substring zu verwenden. */Replace /'' –

+1

@Eddy_Em Das ersetzt die gesamte Zeile mit replace. Sie müssen Gruppierung verwenden, um den Teil der Zeile vor und nach der Teilzeichenfolge zu erfassen und dann in die Ersatzzeile einzufügen. 'sed -i 's/\ (. * \) Teilzeichenfolge \ (. * \)/\ 1Replace \ 2 /'' – JStrahl

Antwort

1

Normalerweise nicht mit grep, sondern mit sed -i 's/string_to_find/another_string/g' oder perl -i.bak -pe 's/string_to_find/another_string/g'.

102

Ich habe die Antwort bekommen.

+11

Das würde die übereinstimmenden Dateien zweimal durchsuchen ... einmal mit 'grep' und dann wieder mit' sed '. 'Find' Methode ist effizienter, aber diese Methode funktioniert. – cmevoli

+24

Unter OS X müssen Sie 'sed -i 's/str1/str2/g' in 'sed -i' ''/str1/str2/g 'ändern, damit dies funktioniert. – jdf

+2

@jdf warum ist das? – chishaku

158

Eine andere Möglichkeit ist, find zu verwenden und dann sed zu übergeben.

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

Unter OS X 10.10 Terminal ist eine richtige Erweiterungszeichenfolge für den Parameter "-i" erforderlich. Zum Beispiel 'find/pfad/zu/files -type f -exec sed -i" "" s/oldstring/new string/g "{} \;' Wie auch immer, wenn ein leerer String zur Verfügung gestellt wird, wird eine Backup-Datei erstellt ... – Eonil

+5

Warum bekomme ich "sed: RE Fehler: illegale Byte-Sequenz". Und ja, ich habe das '-i '" 'für OS X hinzugefügt. Es funktioniert anders. – taco

+0

Ich hatte die illegale Bytefolge auf Mac OS 10.12, und diese Frage/Antwort löste mein Problem: http://StackOverflow.com/questions/19242275/re-error-illegal-byte-sequence-on-mac-os-x . – abeboparebop

25

Dies funktioniert am besten für mich auf OS X:

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

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

+0

das ist perfekt! funktioniert auch mit ag: 'ag" search "-l -r. | sortieren | uniq | xargs perl -e 's/search/replace' -pi' –

+1

'sort -u' kann' sort | ersetzen uniq' –

+0

@sebastiankeller Ihr Perl-Befehl fehlt der abschließende Schrägstrich, der ein Syntaxfehler ist. – tripleee

0

Eine weitere Option nur wäre Perl zu verwenden, mit globstar.

Aktivieren shopt -s globstar in Ihrer .bashrc (oder wo auch immer) ermöglicht die ** Glob Muster alle Unterverzeichnisse und Dateien rekursiv übereinstimmen.

Mit perl -pXe 's/SEARCH/REPLACE/g' -i ** wird also rekursiv ersetzen SEARCH mit REPLACE.

Das -X Flag sagt perl zu "alle Warnungen deaktivieren" - was bedeutet, dass es über Verzeichnisse nicht klagen wird.

Die globstar können Sie auch Dinge wie sed -i 's/SEARCH/REPLACE/g' **/*.ext tun, wenn Sie SEARCH mit REPLACE in allen untergeordneten Dateien mit der Endung .ext ersetzen wollen.

+0

* "Eine andere Option wäre, Perl mit globstar zu verwenden ..." * - Nicht auf Posixy-Maschinen wie Solaris. Deshalb suche ich gezielt nach 'grep' und' sed'. – jww

19

Sie selbst wie diese folgen könnte ..

Beispiel

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

Dies wird für die Zeichenfolge ‚Fenster‘ in allen Dateien relativ zum aktuellen Verzeichnis suchen und ersetzen "Fenster 'mit' linux 'für jedes Auftreten der Zeichenfolge in jeder Datei.

+2

Das 'grep' ist nur nützlich, wenn es Dateien gibt, die nicht geändert werden sollen.Wird 'sed' für alle Dateien ausgeführt, wird das Änderungsdatum der Datei aktualisiert, der Inhalt wird jedoch unverändert gelassen, wenn keine Übereinstimmungen vorhanden sind. – tripleee

+0

@tripleee: Seien Sie vorsichtig mit * ..., aber [sed] lassen Sie den Inhalt unverändert, wenn keine Übereinstimmungen vorhanden sind "*. Wenn Sie' -i' verwenden, ändert 'sed' die Dateizeit jeder Datei, die sie berührt obwohl der Inhalt unverändert ist. 'sed' konvertiert auch Zeilenendungen. Ich benutze' sed' nicht unter Windows in einem Git Repo weil alle 'CRLF' in' LF' geändert werden. – jww

3

Andere Lösungen mischen Regex-Syntax. Um perl/PCRE-Muster für sowohl Suchen und Ersetzen, und vermeiden Sie jede Datei der Verarbeitung, das funktioniert ganz gut:

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

wo match1 und match2 in der Regel identisch sind, aber match1 vereinfacht werden kann erweiterte Funktionen zu entfernen, sind nur für die Substitution relevant, z Gruppen erfassen.

Übersetzung: grep rekursiv und Liste übereinstimmende Dateien, getrennt durch Null zum Schutz von Sonderzeichen im Dateinamen, die diese PCRE-Muster entsprechen, dann Pipe diese Dateinamen zu Xargs, die eine leere Liste erwartet, aber nicht tue alles, wenn keine Namen empfangen werden, und erhalte perl, um jede Datei neu zu schreiben, wobei Zeilen ersetzt werden, in denen Übereinstimmungen gefunden werden.

Fügen Sie die I Option zu grep hinzu, um auch Binärdateien zu ignorieren.

+0

Perl ist durchaus in der Lage, eine Datei zu rekursiv zu machen Tatsächlich gibt es ein Tool ['find2perl'] (https://perldoc.perl.org/5.8.8/find2perl.html), das mit Perl geliefert wird, was so etwas ohne" xargs "Tricks macht. – tripleee

+0

@tripleee 'find' sucht nicht nach Dateiinhalten, und der Punkt besteht darin, nur übereinstimmende Dateien zu verarbeiten, ohne ein Perl-Programm zu schreiben. – Walf

-3

finden & in vi Modus einer Datei ersetzen Die Syntax ist wie folgt: :% s/WORD-To-Find-HIER/Ersetzen-Wort-Here/g

OR :% s/FindMe/ReplaceME/g

Beispiele

Der Ersatz Befehl kann wie pro Ihre Anforderungen verwendet werden.