Ich muss rekursiv nach einer angegebenen Zeichenfolge in allen Dateien und Unterverzeichnissen in einem Verzeichnis suchen und diese Zeichenfolge durch eine andere Zeichenfolge ersetzen.
Ich weiß, dass der Befehl zum Finden folgendermaßen aussehen könnte:
grep 'string_to_find' -r ./*
Aber wie kann ich jede Instanz von string_to_find
durch eine andere Zeichenfolge ersetzen ?
sed -i 's/.*substring.*/replace/'
sed -i 's/\(.*\)substring\(.*\)/\1replace\2/'
Antworten:
Eine andere Möglichkeit besteht darin, find zu verwenden und es dann durch sed zu leiten.
quelle
-i
erforderlich. Wenn Sie beispielsweisefind /path/to/files -type f -exec sed -i "" "s/oldstring/new string/g" {} \;
eine leere Zeichenfolge-i ""
für OS X hinzugefügt. Es funktioniert anders.CRLF
bisLF
unter Windows.Ich habe die Antwort bekommen.
quelle
grep
und dann noch einmal mitsed
. Die Verwendung derfind
Methode ist effizienter, aber diese von Ihnen erwähnte Methode funktioniert.sed -i 's/str1/str2/g'
,sed -i "" 's/str1/str2/g'
damit dies funktioniert.grep
alle Dateien durch undsed
scannt nur die Dateien, die mit übereinstimmengrep
. Mit derfind
Methode in der anderen Antwort werdenfind
zuerst alle Dateien aufgelistet und dannsed
alle Dateien in diesem Verzeichnis durchsucht. So dass diese Methode nicht unbedingt langsamer ist, hängt davon ab , wie viele Spiele gibt es , und die Unterschiede in den Suchgeschwindigkeiten zwischensed
,grep
undfind
.Sie könnten es sogar so machen:
Beispiel
Dadurch wird in allen Dateien relativ zum aktuellen Verzeichnis nach der Zeichenfolge ' windows ' gesucht und ' windows ' bei jedem Auftreten der Zeichenfolge in jeder Datei durch ' linux ' ersetzt.
quelle
grep
ist nur nützlich, wenn Dateien vorhanden sind, die nicht geändert werden sollten. Laufensed
auf allen Dateien aktualisieren das Änderungsdatum der Datei , aber lassen Sie die Inhalte unverändert , wenn es keine Übereinstimmungen gibt.-i
meiner Meinungsed
nach die Dateizeit jeder Datei, die berührt wird, obwohl der Inhalt unverändert bleibt.sed
Konvertiert auch Zeilenenden Ich verwende es nichtsed
unter Windows in einem Git-Repo, da alleCRLF
in geändert wurdenLF
.Dies funktioniert am besten für mich unter OS X:
Quelle: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files
quelle
ag "search" -l -r . | sort | uniq | xargs perl -e 's/search/replace' -pi
sort -u
gerade Teil davon? Unter welchen Umständen würden Sie erwartengrep -rl
, zweimal denselben Dateinamen zu erstellen?Andere Lösungen mischen Regex-Syntaxen. Um Perl / PCRE-Muster sowohl zum Suchen als auch zum Ersetzen zu verwenden und nur übereinstimmende Dateien zu verarbeiten, funktioniert dies recht gut:
wo
match1
undmatch2
sind normalerweise identisch,match1
können aber vereinfacht werden, um erweiterte Funktionen zu entfernen, die nur für die Ersetzung relevant sind, z. B. das Erfassen von Gruppen.Übersetzung:
grep
rekursiv und Listen von Dateien, die diesem PCRE-Muster entsprechen, durch nul getrennt, um Sonderzeichen im Dateinamen zu schützen, und dann die Dateinamen weiterzuleiten,xargs
die eine durch Null getrennte Liste erwarten, aber nichts tun, wenn keine Namen empfangen werden. undperl
zu Ersatzzeilen gelangen , in denen Übereinstimmungen gefunden werden.Fügen Sie den
I
Schalter hinzugrep
, um Binärdateien zu ignorieren. Löschen Sie für Übereinstimmungen zwischen Groß- und Kleinschreibung deni
Schalter vongrep
und dasi
Flag, das an den Substitutionsausdruck angehängt ist, aber nicht deni
Schalter anperl
sich.quelle
find2perl
das im Lieferumfang von Perl enthalten ist und solche Dinge ohnexargs
Tricks erledigt .find
keine Dateiinhalte und es geht darum, nur übereinstimmende Dateien zu verarbeiten, ohne ein Perl-Programm zu schreiben.Normalerweise nicht mit grep, sondern mit
sed -i 's/string_to_find/another_string/g'
oderperl -i.bak -pe 's/string_to_find/another_string/g'
.quelle
Seien Sie sehr vorsichtig bei der Verwendung
find
undsed
in einem Git Repo! Wenn Sie die Binärdateien nicht ausschließen, kann dieser Fehler auftreten:Um diesen Fehler zu beheben, müssen Sie den Fehler beheben,
sed
indem Sie Ihrennew_string
durch Ihren ersetzenold_string
. Dadurch werden Ihre ersetzten Zeichenfolgen zurückgesetzt, sodass Sie wieder am Anfang des Problems stehen.Der richtige Weg, um nach einem String zu suchen und ihn zu ersetzen, besteht darin, ihn zu überspringen
find
undgrep
stattdessen zu verwenden, um die Binärdateien zu ignorieren:Credits für @hobs
quelle
Folgendes würde ich tun:
Dies sucht nach allen Dateien, die
filename
im Dateinamen unter der/path/to/dir
Option enthalten sind, und sucht nach der Zeile mitsearchstring
und ersetztold
durchnew
.Wenn Sie jedoch die Suche nach einer bestimmten Datei mit einer
filename
Zeichenfolge im Dateinamen unterlassen möchten, tun Sie einfach Folgendes:Dies wird das Gleiche wie oben tun, jedoch für alle Dateien, die unter gefunden werden
/path/to/dir
.quelle
Eine andere Möglichkeit wäre, nur Perl mit Globstar zu verwenden.
Durch Aktivieren
shopt -s globstar
in Ihrem.bashrc
(oder wo auch immer) kann das**
Glob-Muster rekursiv mit allen Unterverzeichnissen und Dateien übereinstimmen.So verwenden
perl -pXe 's/SEARCH/REPLACE/g' -i **
rekursiv ersetzenSEARCH
mitREPLACE
.Das
-X
Flag weist Perl an, "alle Warnungen zu deaktivieren" - was bedeutet, dass es sich nicht über Verzeichnisse beschwert.Der globstar ermöglicht es Ihnen auch , wie die Dinge zu tun ,
sed -i 's/SEARCH/REPLACE/g' **/*.ext
wenn man wollte ersetzenSEARCH
mitREPLACE
in allen untergeordneten Dateien mit der Erweiterung.ext
.quelle
grep
undsed
.