Der folgende Befehl ändert den Inhalt von 2 Dateien korrekt.
sed -i 's/abc/xyz/g' xaa1 xab1
Was ich aber tun muss, ist, mehrere solcher Dateien dynamisch zu ändern, und ich kenne die Dateinamen nicht. Ich möchte einen Befehl schreiben, der alle Dateien aus dem aktuellen Verzeichnis liest, beginnend mit xa*
und sed
den Dateiinhalt ändern soll.
sed -i 's/abc/xyz/g' xa*
?Antworten:
Besser noch:
weil niemand weiß, wie viele Dateien vorhanden sind und es einfach ist, Befehlszeilenlimits zu überschreiten.
Folgendes passiert, wenn zu viele Dateien vorhanden sind:
quelle
for
. Um sichfind ... | xargs ...
for
als fürecho
odergrep
?"$i"
anstelle von verwenden$i
, um die Wortteilung bei Dateinamen mit Leerzeichen zu vermeiden. Ansonsten ist das sehr schön.for
es Teil der Sprachsyntax ist, nicht einmal nur eine eingebaute. Dennsed -i 's/old/new' *
die Erweiterung von*
muss ALL als Arglist an sed übergeben werden, und ich bin mir ziemlich sicher, dass dies geschehen muss, bevor dersed
Prozess überhaupt gestartet werden kann. Bei Verwendung derfor
Schleife wird die vollständige Arglist (die Erweiterung von*
) niemals als Befehl übergeben, sondern nur im Shell-Speicher gespeichert und durchlaufen. Ich habe dafür überhaupt keine Referenz, es scheint nur wahrscheinlich, dass dies der Unterschied ist. (Ich würde gerne von jemandem hören, der besser informiert ist ...)Ich bin überrascht, dass niemand das zu findende Argument -exec erwähnt hat, das für diese Art von Anwendungsfall vorgesehen ist, obwohl für jeden übereinstimmenden Dateinamen ein Prozess gestartet wird:
Alternativ könnte man xargs verwenden, wodurch weniger Prozesse aufgerufen werden:
Oder verwenden Sie einfach die
+
exec-Variante anstelle von;
in find, damit find mehr als eine Datei pro Unterprozessaufruf bereitstellen kann:quelle
find ./ -type f -name 'xa*' -exec sed -i '' 's/asd/dsg/g' {} \;
Das ist der Speicherort für den Befehl find./
und ein paar einfache Anführungszeichen danach-i
für OSX../
ist gleich.
und-i
hat nur den Parameter backupsuffix.-exec
Option, zusammen mit zu finden,{} +
reicht aus, um das angegebene Problem zu lösen, und sollte für die meisten Anforderungen in Ordnung sein. Istxargs
aber im Allgemeinen eine bessere Wahl, da es auch die parallele Verarbeitung mit der-p
Option ermöglicht. Wenn Ihre Glob-Erweiterung groß genug ist, um Ihre Befehlszeilenlänge zu überschreiten, profitieren Sie wahrscheinlich auch von einer Beschleunigung über einen sequentiellen Lauf.Sie könnten grep und sed zusammen verwenden. Auf diese Weise können Sie Unterverzeichnisse rekursiv durchsuchen.
quelle
grep -v
git-Ordner schlüpfen konntegrep -rl <old> . | grep -v \.git | xargs sed -i 's/<old>/<new>/g'
Diese Befehle funktionieren nicht in der Standardeinstellung
sed
von Mac OS X.Von
man 1 sed
:Versucht
und
Beide funktionieren gut.
quelle
@PaulR hat dies als Kommentar gepostet, aber die Leute sollten es als Antwort ansehen (und diese Antwort funktioniert am besten für meine Bedürfnisse):
Dies funktioniert für eine moderate Anzahl von Dateien, wahrscheinlich in der Größenordnung von zehn, aber wahrscheinlich nicht in der Größenordnung von Millionen .
quelle
sed -i 's|auth-user-pass nordvpn.txt|auth-user-pass /etc/openvpn/nordvpn.txt|g' *.ovpn
.Eine andere vielseitigere Möglichkeit ist die Verwendung von
find
:quelle
Ich benutze
find
für ähnliche Aufgabe. Es ist ganz einfach: Sie müssen es als Argument fürsed
Folgendes übergeben:sed -i 's/EXPRESSION/REPLACEMENT/g' `find -name "FILE.REGEX"`
Auf diese Weise müssen Sie keine komplexen Schleifen schreiben, und es ist einfach zu erkennen, welche Dateien Sie ändern möchten. Führen
find
Sie sie einfach aus, bevor Sie sie ausführensed
.quelle
du kannst machen
' xxxx ' Text wird gesucht und durch ' JJJJ ' ersetzt.
quelle
Wenn Sie ein Skript ausführen können, habe ich Folgendes für eine ähnliche Situation getan:
Mithilfe eines Wörterbuchs / einer HashMap (assoziatives Array) und von Variablen für den
sed
Befehl können wir das Array durchlaufen, um mehrere Zeichenfolgen zu ersetzen. Wenn Sie einen Platzhalter in das Verzeichnisname_pattern
einfügen, können Sie diese in Dateien durch ein Muster (dies könnte etwa so seinname_pattern='File*.txt'
) in einem bestimmten Verzeichnis (source_dir
) ersetzen . Alle Änderungen sind in derlogfile
in der geschriebendestin_dir
Zuerst wird die Paare Array deklariert, ist jedes Paar eine Ersatzzeichenfolge, dann
WHAT1
wird für die ersetzt werdenFOR1
undOTHER_string_to replace
wird ersetztstring replaced
in der DateiFile.txt
. In der Schleife wird das Array gelesen, das erste Mitglied des Paares wird alsreplace_what=$i
und das zweite als abgerufenreplace_for=$j
. Derfind
Befehl durchsucht im Verzeichnis den Dateinamen (der möglicherweise einen Platzhalter enthält) und dersed -i
Befehl ersetzt in derselben Datei (en) die zuvor definierten. Schließlich habe ichgrep
der Protokolldatei eine umgeleitete Datei hinzugefügt , um die in den Dateien vorgenommenen Änderungen zu protokollieren.Dies funktionierte für mich in
GNU Bash 4.3
sed 4.2.2
und basierte auf VasyaNovikovs Antwort für Loop over Tuples in Bash .quelle