Wie kann ich mit einer Shell wie bash oder zshell ein rekursives Suchen und Ersetzen durchführen? Mit anderen Worten, ich möchte jedes Vorkommen von 'foo' durch 'bar' in allen Dateien in diesem Verzeichnis und seinen Unterverzeichnissen ersetzen.
bash
shell
zsh
find-and-replace
Nathan Long
quelle
quelle
Antworten:
Dieser Befehl wird es tun (getestet auf Mac OS X Lion und Kubuntu Linux).
So funktioniert das:
find . -type f -name '*.txt'
findet im aktuellen Verzeichnis (.
) und darunter alle regulären Dateien (-type f
), deren Namen auf enden.txt
|
Übergibt die Ausgabe dieses Befehls (eine Liste von Dateinamen) an den nächsten Befehlxargs
sammelt diese Dateinamen und übergibt sie einzeln ansed
sed -i '' -e 's/foo/bar/g'
bedeutet "Bearbeiten Sie die Datei an Ort und Stelle, ohne eine Sicherung, und nehmen Sie die folgende Ersetzung (s/foo/bar
) mehrmals pro Zeile (/g
) vor" (sieheman sed
)Beachten Sie, dass der Teil 'ohne Backup' in Zeile 4 für mich in Ordnung ist, da die Dateien, die ich ändere, sowieso unter Versionskontrolle stehen, sodass ich bei einem Fehler leicht rückgängig machen kann.
quelle
-print0
Option senden . Ihr Befehl schlägt bei Dateien mit Leerzeichen usw. im Namen fehl.find -name '*.txt' -exec sed -i 's/foo/bar/g' {} +
werde das alles auch mit GNU find machen.sed: can't read : No such file or directory
wenn ich laufefind . -name '*.md' -print0 | xargs -0 sed -i '' -e 's/ä/ä/g'
, aberfind . -name '*.md' -print0
eine Liste mit vielen Dateien.-i
und dem''
''
nach dem,sed -i
was ist die''
Rolle?Dadurch wird die
xargs
Abhängigkeit entfernt.quelle
sed
, wird also auf den meisten Systemen fehlschlagen. GNUsed
verlangt, dass Sie kein Leerzeichen zwischen-i
und setzen''
.Wenn Sie Git verwenden, können Sie dies tun:
-l
listet nur Dateinamen auf.-z
gibt nach jedem Ergebnis ein Null-Byte aus.Am Ende tat ich dies, weil einige Dateien in einem Projekt keine neue Zeile am Ende der Datei hatten und sed eine neue Zeile hinzufügte, selbst wenn keine anderen Änderungen vorgenommen wurden. (Kein Kommentar, ob Dateien am Ende eine neue Zeile haben sollen oder nicht. 🙂)
quelle
find ... -print0 | xargs -0 sed ...
Lösungen dauert nicht nur viel länger, sondern fügt auch neue Zeilen zu Dateien hinzu, die noch keine haben. Dies ist ein Ärgernis, wenn Sie in einem Git-Repo arbeiten.git grep
ist im Vergleich schnell beleuchtet.Hier ist meine zsh / perl-Funktion, die ich dafür benutze:
Und ich würde es mit ausführen
(zum Beispiel)
quelle
Versuchen:
Getestet unter Ubuntu 12.04.
Dieser Befehl funktioniert NICHT, wenn die Namen und / oder Dateinamen von Unterverzeichnissen Leerzeichen enthalten. Wenn Sie diese haben, verwenden Sie diesen Befehl nicht, da er nicht funktioniert.
Es ist im Allgemeinen eine schlechte Praxis, Leerzeichen in Verzeichnis- und Dateinamen zu verwenden.
http://linuxcommand.org/lc3_lts0020.php
Schauen Sie sich "Wichtige Fakten zu Dateinamen" an.
quelle
Verwenden Sie dieses Shell-Skript
Ich verwende jetzt dieses Shell-Skript, das Dinge kombiniert, die ich aus den anderen Antworten und aus der Suche im Web gelernt habe. Ich legte es in eine Datei namens
change
in einem Ordner auf meinem$PATH
und tat eschmod +x change
.quelle
Mein Anwendungsfall war ich ersetzen wollte
foo:/Drive_Letter
mitfoo:/bar/baz/xyz
konnte ich tun , um es mit dem folgenden Code in meinem Fall. Ich befand mich im selben Verzeichnis, in dem sich viele Dateien befanden.hoffe das hat geholfen.
quelle
Der folgende Befehl funktionierte unter Ubuntu und CentOS einwandfrei. Unter OS XI gab es jedoch immer wieder Fehler:
Als ich versuchte, die Parameter über xargs zu übergeben, funktionierte das ohne Fehler:
quelle
-i
zu-i ''
ist wahrscheinlich wichtiger als die Tatsache , dass Sie geändert-exec
zu-print0 | xargs -0
. Übrigens brauchen Sie das wahrscheinlich nicht-e
.Das Obige hat wie ein Zauber funktioniert, aber bei verknüpften Verzeichnissen muss ich ein
-L
Flag hinzufügen . Die endgültige Version sieht so aus:quelle