Ich versuche, eine Zeichenfolge in allen Dateien zu suchen und zu ersetzen, die mit grep auf einem Linux-Computer übereinstimmen. Ich habe einige Teile von dem, was ich tun möchte, bin mir aber nicht sicher, wie ich sie am besten aneinander reihen soll.
grep -n 'foo' *
wird mir Ausgabe in der Form geben:
[filename]:[line number]:[text]
Für jede von grep zurückgegebene Datei möchte ich "foo" durch "bar" ersetzen und das Ergebnis in die Datei zurückschreiben. Gibt es eine gute Möglichkeit, das zu tun? Vielleicht eine schicke Pipeline?
Antworten:
Meinen Sie das Suchen und Ersetzen einer Zeichenfolge in allen Dateien, die mit grep übereinstimmen?
perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`
Bearbeiten
Da dies eine ziemlich beliebte Frage zu sein scheint, dachte ich, ich würde sie aktualisieren.
Heutzutage benutze ich meistens,
ack-grep
weil es benutzerfreundlicher ist. Der obige Befehl wäre also:perl -p -i -e 's/old/new/g' `ack -l searchpattern`
So behandeln Sie Leerzeichen in Dateinamen:
ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'
Sie können mehr damit machen
ack-grep
. Angenommen, Sie möchten die Suche nur auf HTML-Dateien beschränken:ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'
Und wenn Leerraum kein Thema ist, ist er noch kürzer:
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
quelle
Can't open Untitled: No such file or directory, <> line 5
beim Versuch "Untitled Folder / file.txt".Dies scheint das zu sein, was Sie wollen, basierend auf dem Beispiel, das Sie gegeben haben:
sed -i 's/foo/bar/g' *
Es ist nicht rekursiv (es wird nicht in Unterverzeichnisse absteigen). Für eine nette Lösung, die in ausgewählten Dateien in einem Baum ersetzt wird, würde ich find verwenden:
find . -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
Das
*.html
ist der Ausdruck , dass Dateien müssen übereinstimmen, die.bak
nach dem-i
eine Kopie der Originaldatei macht, mit der Erweiterung .bak (es kann jede Erweiterung , die Sie wie sein) und derg
am Ende des sed Ausdruck Tells auf mehrere Kopien sed ersetzen eine Zeile (und nicht nur die erste). Das-print
zu finden ist eine Bequemlichkeit, um zu zeigen, welche Dateien abgeglichen wurden. All dies hängt von den genauen Versionen dieser Tools auf Ihrem System ab.quelle
find
Befehl ein Verzeichnis geben, von dem aus Sie beispielsweisefind . -name '*.html'
oder starten könnenfind directoryname/ -name '*'
.sed -ie 's/foo/bar/g' *
Wenn Sie
sed(1)
eine-i
Option haben, verwenden Sie diese wie folgt:for i in *; do sed -i 's/foo/bar/' $i done
Wenn nicht, gibt es verschiedene Möglichkeiten, je nachdem, mit welcher Sprache Sie spielen möchten:
ruby -i.bak -pe 'sub(%r{foo}, 'bar')' * perl -pi.bak -e 's/foo/bar/' *
quelle
for i in *; do ...
Ist redundant, kann sed eine Liste von Dateien als Argumente verwenden.for i in *; do; sed -i 's/foo/bar/g' "$i"; done
Ich mag und verwende die obige Lösung oder eine systemweite Suche und Ersetzung unter Tausenden von Dateien:
find -name '*.htm?' -print -exec sed -i.bak 's/foo/bar/g' {} \;
Ich nehme an mit dem '* .htm?' Anstelle von .html werden .htm- und .html-Dateien gleichermaßen gesucht und gefunden.
Ich ersetze die .bak durch die systemweit verwendete Tilde (~), um das Bereinigen von Sicherungsdateien zu vereinfachen.
quelle
Dies funktioniert mit grep, ohne dass Perl oder Find verwendet werden muss.
grep -rli 'old-word' * | xargs -i@ sed -i 's/old-word/new-word/g' @
quelle
-i
es für andere Betriebssysteme nicht funktioniert. Funktioniert für mich auf Ubuntu.xargs
Manpage (unter Ubuntu) sagt, dass dies-i
veraltet ist und-I
stattdessen verwendet werden soll. Also sollten wir sagen:grep -rli 'old-word' * | xargs -I filepath sed -i 's/old-word/new-word/g' filepath
find . -type f -print0 | xargs -0 <sed/perl/ruby cmd>
verarbeitet mehrere in Speicherplätzen enthaltene Dateinamen gleichzeitig und lädt einen Interpreter pro Stapel. Viel schneller.quelle
Die bereits gegebene Antwort auf die Verwendung von find und sed
find -name '*.html' -print -exec sed -i.bak 's/foo/bar/g' {} \;
ist wahrscheinlich die Standardantwort. Oder Sie könnten
perl -pi -e s/foo/bar/g'
anstelle dessed
Befehls verwenden.Für die meisten schnellen Anwendungen ist der Befehl rpl möglicherweise leichter zu merken. Hier ist eine rekursive Ersetzung (foo -> bar) für alle Dateien im aktuellen Verzeichnis:
rpl -R foo bar .
Es ist in den meisten Linux-Distributionen nicht standardmäßig verfügbar, lässt sich jedoch schnell installieren (
apt-get install rpl
oder ähnliches).Für härtere Jobs, die reguläre Ausdrücke und Rückersetzung oder das Umbenennen von Dateien sowie das Suchen und Ersetzen beinhalten, ist das allgemeinste und leistungsfähigste Tool, das mir bekannt ist, repren , ein kleines Python-Skript, das ich vor einiger Zeit für einige geschrieben habe dornigere Umbenennungs- und Refactoring-Aufgaben. Die Gründe, die Sie vielleicht bevorzugen, sind:
Überprüfen Sie die README für Beispiele.
quelle
Das ist eigentlich einfacher als es scheint.
grep -Rl 'foo' ./ | xargs -n 1 -I % sh -c "ls %; sed -i 's/foo/bar/g' %";
Kinderleicht. Wenn Sie einen guten Überblick über find, grep, xargs, sed und awk haben, ist fast nichts unmöglich, wenn es um die Manipulation von Textdateien in bash geht :)
quelle