Das Ersetzen von Zeichenfolgen in Dateien anhand bestimmter Suchkriterien ist eine sehr häufige Aufgabe. Wie kann ich
- String ersetzt
foo
mitbar
in allen Dateien im aktuellen Verzeichnis? - Dasselbe rekursiv für Unterverzeichnisse?
- Nur ersetzen, wenn der Dateiname mit einer anderen Zeichenfolge übereinstimmt?
- Nur ersetzen, wenn die Zeichenfolge in einem bestimmten Kontext gefunden wird?
- Ersetzen, wenn sich die Zeichenfolge in einer bestimmten Zeilennummer befindet?
- Ersetzen Sie mehrere Zeichenfolgen durch denselben Ersatz
- Ersetzen Sie mehrere Zeichenfolgen durch unterschiedliche Ersetzungen
text-processing
awk
sed
perl
terdon
quelle
quelle
Antworten:
1. Ersetzen aller Vorkommen einer Zeichenfolge durch eine andere in allen Dateien im aktuellen Verzeichnis:
In diesen Fällen wissen Sie , dass das Verzeichnis nur reguläre Dateien enthält und dass Sie alle nicht ausgeblendeten Dateien verarbeiten möchten. Ist dies nicht der Fall, verwenden Sie die Ansätze in 2.
Alle
sed
Lösungen in dieser Antwort gehen von GNU aussed
. Wenn Sie FreeBSD oder OS / X verwenden, ersetzen Sie-i
durch-i ''
. Beachten Sie außerdem, dass die Verwendung des-i
Switches mit einer beliebigen Version vonsed
bestimmte Auswirkungen auf die Sicherheit des Dateisystems hat und in keinem Skript empfohlen wird, das Sie auf irgendeine Weise verteilen möchten.Nicht rekursiv, nur Dateien in diesem Verzeichnis:
(Der
perl
Fehler tritt bei Dateinamen auf, die auf|
oder mit Leerzeichen enden ).Rekursive, reguläre Dateien ( einschließlich versteckter ) in diesem und allen Unterverzeichnissen
Wenn Sie zsh verwenden:
(Kann fehlschlagen, wenn die Liste zu groß ist. Sehen Sie
zargs
, um das Problem zu umgehen .)Bash kann nicht direkt nach regulären Dateien suchen, es wird eine Schleife benötigt (geschweifte Klammern vermeiden es, die Optionen global zu setzen):
Die Dateien werden ausgewählt, wenn es sich um tatsächliche Dateien handelt (-f) und beschreibbar sind (-w).
2. Ersetzen Sie nur, wenn der Dateiname mit einer anderen Zeichenfolge übereinstimmt / eine bestimmte Erweiterung hat / von einem bestimmten Typ ist usw.:
Nicht rekursive Dateien nur in diesem Verzeichnis:
Rekursive, reguläre Dateien in diesem und allen Unterverzeichnissen
Wenn Sie bash verwenden (geschweifte Klammern vermeiden es, die Optionen global festzulegen):
Wenn Sie zsh verwenden:
Das
--
dient dazu mitzuteilen,sed
dass in der Kommandozeile keine Flags mehr vergeben werden. Dies ist nützlich, um vor Dateinamen zu schützen, die mit beginnen-
.Wenn eine Datei von einem bestimmten Typ ist, z. B. ausführbar (siehe
man find
für weitere Optionen):zsh
:3. Ersetzen Sie nur, wenn die Zeichenfolge in einem bestimmten Kontext gefunden wird
Ersetzen Sie
foo
mitbar
nur, wenn esbaz
später in derselben Zeile gibt:In
sed
, mit\( \)
spart , was in den Klammern ist und Sie können es dann Zugriff mit\1
. Es gibt viele Variationen dieses Themas, um mehr über solche regulären Ausdrücke zu erfahren, siehe hier .Nur ersetzen
foo
durchbar
, wennfoo
in der 3d-Spalte (Feld) der Eingabedatei gefunden wird (unter der Annahme von durch Leerzeichen getrennten Feldern):(benötigt
gawk
4.1.0 oder neuer).Verwenden Sie für ein anderes Feld einfach,
$N
woN
die Nummer des gewünschten Feldes ist.:
Verwenden Sie für ein anderes Feldtrennzeichen ( in diesem Beispiel):Eine andere Lösung mit
perl
:HINWEIS: Sowohl die
awk
als auch dieperl
Lösungen wirken sich auf den Abstand in der Datei aus (entfernen Sie die führenden und nachfolgenden Leerzeichen und konvertieren Sie die Folgen von Leerzeichen in ein Leerzeichen in den übereinstimmenden Zeilen). Verwenden Sie für ein anderes Feld,$F[N-1]
woN
die gewünschte Feldnummer ist, und für ein anderes Feld das Trennzeichen (das$"=":"
setzt das Ausgabefeldtrennzeichen auf:
):Ersetzen Sie
foo
mitbar
nur in der 4. Zeile:4. Mehrere Ersetzungsoperationen: Ersetzen durch verschiedene Zeichenfolgen
Sie können
sed
Befehle kombinieren :Beachten Sie, dass , um Angelegenheiten (
sed 's/foo/bar/g; s/bar/baz/g'
wird ersetztfoo
mitbaz
).oder Perl-Befehle
Wenn Sie über eine große Anzahl von Mustern verfügen, ist es einfacher, Ihre Muster und ihre Ersetzungen in einer
sed
Skriptdatei zu speichern:Wenn Sie zu viele Musterpaare haben, als dass dies möglich wäre, können Sie Musterpaare aus einer Datei lesen (zwei durch Leerzeichen getrennte Muster, $ pattern und $ replacement pro Zeile):
Bei langen Listen mit Mustern und großen Datendateien ist dies recht langsam. Sie können also die Muster lesen und
sed
stattdessen ein Skript daraus erstellen . Im Folgenden wird davon ausgegangen, dass ein <Leerzeichen> eine Liste von MATCH <Leerzeichen> REPLACE- Paaren trennt , die zeilenweise in der Datei vorkommenpatterns.txt
:Das obige Format ist weitgehend willkürlich und lässt beispielsweise weder in MATCH noch in REPLACE ein <Leerzeichen> zu . Die Methode ist jedoch sehr allgemein: Wenn Sie einen Ausgabestream erstellen können, der wie ein Skript aussieht , können Sie diesen Stream als Skript ausgeben , indem Sie die Skriptdatei von stdin angeben.
sed
sed
sed
-
Sie können mehrere Skripte auf ähnliche Weise kombinieren und verketten:
Ein POSIX
sed
verknüpft alle Skripte in der Reihenfolge, in der sie in der Befehlszeile angezeigt werden, zu einem Skript. Keines von diesen muss in einer\n
ewline enden.grep
kann auf die gleiche Weise arbeiten:Wenn Sie mit festen Zeichenfolgen als Mustern arbeiten, ist es empfehlenswert, Metazeichen mit regulären Ausdrücken zu umgehen . Sie können dies ziemlich einfach tun:
5. Mehrere Ersetzungsoperationen: Ersetzen Sie mehrere Muster durch dieselbe Zeichenfolge
Ersetzen jeder
foo
,bar
oderbaz
mitfoobar
oder
quelle
zsh
. Füge auf jeden Fallzsh
Informationen hinzu, aber es gibt keinen Grund, das Bash-Zeug zu entfernen. Ich weiß auch, dass die Verwendung der Shell für die Textverarbeitung nicht ideal ist, aber es gibt Fälle, in denen dies erforderlich ist. Ich habe eine bessere Version meines ursprünglichen Skripts verwendet, mit der einsed
Skript erstellt wird, anstatt die Shell-Schleife zum Parsen zu verwenden. Dies kann nützlich sein, wenn Sie beispielsweise mehrere hundert Musterpaare haben.(.)
Globbing-Qualifikationsmerkmal und kann daher hier nicht verwendet werden. (Sie vermissen einige - auch). Die for-Schleife ist falsch (fehlende -r) und bedeutet, dass mehrere Durchgänge in den Dateien ausgeführt werden und kein Vorteil gegenüber einem sed-Skript entsteht.--
nachsed -i
und vor dem Ersatzbefehl?-
. Durch die Verwendung wird sichergestellt, dass die Befehle für Dateien mit Namen wie "" funktionieren-foo
. Ohne sie-f
würde das als eine Option analysiert werden..git
Verzeichnis geändert und Ihre Kasse tatsächlich durcheinander gebracht. Es ist besser, in bestimmten Verzeichnissen nach Namen zu arbeiten.Ein guter r e pl acement Linux - Tool ist RPL , das ursprünglich für das Debian - Projekt geschrieben wurde, so dass es mit verfügbar ist
apt-get install rpl
in jedem Debian abgeleitete Distribution und für andere sein kann, aber ansonsten kann man die Download -tar.gz
Datei in SourgeForge .Einfachstes Anwendungsbeispiel:
Beachten Sie, dass die Zeichenfolge in Anführungszeichen gesetzt werden muss, wenn sie Leerzeichen enthält. Achten Sie standardmäßig
rpl
auf Großbuchstaben, aber nicht auf vollständige Wörter . Sie können diese Standardeinstellungen jedoch mit den Optionen-i
(Groß- / Kleinschreibung ignorieren) und-w
(ganze Wörter) ändern . Sie können auch mehrere Dateien angeben :Oder geben Sie die zu durchsuchenden Erweiterungen (
-x
) an oder durchsuchen Sie das Verzeichnis sogar rekursiv (-R
):Sie können auch im interaktiven Modus mit der
-p
Option (Eingabeaufforderung) suchen / ersetzen :Die Ausgabe zeigt die Anzahl der ersetzten Dateien / Strings und die Art der Suche (Groß- / Kleinschreibung beachten, ganze / teilweise Wörter), kann jedoch mit der Option
-q
( stiller Modus ) oder noch ausführlicherer Auflistung der Zeilennummern stumm geschaltet werden Übereinstimmungen für jede Datei und jedes Verzeichnis mit der Option-v
( ausführlicher Modus ).Andere Optionen, die es wert sind, in Erinnerung zu bleiben, sind
-e
(honor e scapes), die es erlaubenregular expressions
, auch nach Tabulatoren (\t
), neuen Zeilen (\n
) usw. Zu suchen . Auch können Sie verwenden ,-f
um Berechtigungen zu erzwingen (natürlich nur , wenn die Benutzer Schreibrechte haben) und-d
die Änderung times` zu erhalten).Wenn Sie sich nicht sicher sind, welche Funktion genau ausgeführt werden soll, verwenden Sie den
-s
( Simulationsmodus ).quelle
So führen Sie ein Suchen und Ersetzen über mehrere Dateien durch :
Meine besten Ergebnisse kommen von der Verwendung von Perl und Grep (um sicherzustellen, dass die Datei den Suchausdruck hat)
quelle
Sie können Vim im Ex-Modus verwenden:
quelle
Ich habe das benutzt:
Listen Sie alle Dateien auf, die enthalten
old_string
.Ersetzen Sie newline im Ergebnis durch Leerzeichen (damit die Liste der Dateien eingespeist werden kann)
sed
.Führen Sie
sed
diese Dateien aus, um die alte Zeichenfolge durch eine neue zu ersetzen.Update: Das obige Ergebnis schlägt bei Dateinamen fehl, die Leerzeichen enthalten. Verwenden Sie stattdessen:
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'
quelle
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'
wird es mit beliebigen Dateinamen umgehen.Aus Benutzersicht ist dies ein schönes und einfaches Unix-Tool, das die Aufgabe perfekt erledigt
qsubst
. Zum Beispiel,ersetzt
foo
mitbar
in meinen C - Dateien. Ein nettes Feature ist, dassqsubst
eine Abfrage ersetzt wird , dh es zeigt mir jedes Vorkommen vonfoo
und fragt, ob ich es ersetzen möchte oder nicht. [Sie können bedingungslos (ohne zu fragen) durch die-go
Option ersetzen , und es gibt andere Optionen, z. B.-w
wenn Sie nur ersetzen möchten,foo
wenn es sich um ein ganzes Wort handelt.]Wie man es bekommt:
qsubst
Wurde von der Mouse (von McGill) erfunden und im August 1987 auf comp.unix.sources 11 (7) gepostet . Aktualisierte Versionen existieren. Zum Beispielqsubst.c,v 1.8 2004/11/01
kompiliert und läuft die NetBSD-Version perfekt auf meinem Mac.quelle
Ich brauchte etwas , das eine trockenlauf Option bieten würde und rekursiv mit einem glob arbeiten, und nach dem Versuch , es zu tun mit
awk
undsed
ich aufgab und stattdessen tat es in Python.Das Skript durchsucht rekursiv alle Dateien, die einem Glob-Muster entsprechen (z. B.
--glob="*.html"
), nach einem regulären Ausdruck und ersetzt ihn durch den regulären Ausdruck:Jede lange Option wie
--search-regex
hat eine entsprechende kurze Option, dh-s
. Führen Sie mit aus-h
, um alle Optionen anzuzeigen.So werden beispielsweise alle Daten von
2017-12-31
nach gekippt31-12-2017
:quelle
globstar
Option bash (oder die entsprechende Option Ihrer Shell) und**
globs oderfind
. Für einen Trockenlauf verwenden Sie einfachsed
. Sofern Sie diese-i
Option nicht verwenden, werden keine Änderungen vorgenommen. Für ein Backup verwenden Siesed -i.bak
(oderperl -i .bak
); Verwenden Sie für Dateien, die nicht übereinstimmengrep PATTERN file || echo file
. Und warum in aller Welt sollte Python den Glob erweitern, anstatt die Shell dies tun zu lassen? Warumscript.py --glob=foo*
statt nurscript.py foo*
?sed
undawk
gut und nicht bereit sein, zusätzliche Zeit für die Beherrschung zu investieren, (4) Lesbarkeit, (5) diese Lösung funktioniert auch auf nicht-posix-Systemen (nicht, dass ich das brauche, aber jemand anderes könnte).ripgrep ( befehlsname
rg
) ist eingrep
tool, unterstützt aber auch suchen und ersetzen.rg
unterstützt keine In-Place-Option, daher müssen Sie dies selbst tunSiehe Rust regex Dokumentation für Syntax für reguläre Ausdrücke und Funktionen. Der
-P
Schalter aktiviert die PCRE2-Version .rg
unterstützt standardmäßig Unicode.Mit
grep
dieser-F
Option können feste Zeichenfolgen abgeglichen werden, eine praktische Option, die meinessed
Erachtens auch implementiert werden sollte.Eine weitere praktische Option ist
-U
die Möglichkeit des mehrzeiligen Abgleichsrg
Kann auch Dateien im DOS-Stil verarbeitenEin weiterer Vorteil von
rg
ist, dass es wahrscheinlich schneller ist alssed
quelle