GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Wie ersetze ich eine Zeichenfolge in einer oder mehreren Dateien?

Das Ersetzen von Zeichenfolgen in Dateien basierend auf bestimmten Suchkriterien ist eine sehr häufige Aufgabe. Wie kann ich

  • Ersetzen Sie die Zeichenfolge foo mit bar in allen Dateien im aktuellen Verzeichnis?
  • dasselbe rekursiv für Unterverzeichnisse tun?
  • nur ersetzen, wenn der Dateiname mit einer anderen Zeichenfolge übereinstimmt?
  • nur ersetzen, wenn der String in einem bestimmten Kontext gefunden wird?
  • Ersetzen, wenn der String auf einer bestimmten Zeilennummer steht?
  • mehrere Zeichenfolgen durch denselben Ersatz ersetzen
  • mehrere Zeichenfolgen durch unterschiedliche Ersetzungen ersetzen

Akzeptierte Antwort:

1. Ersetzen aller Vorkommen einer Zeichenfolge durch eine andere in allen Dateien im aktuellen Verzeichnis:

Diese sind für Fälle, in denen Sie wissen dass das Verzeichnis nur reguläre Dateien enthält und Sie alle nicht versteckten Dateien verarbeiten möchten. Wenn dies nicht der Fall ist, verwenden Sie die Ansätze in 2.

Alle sed Lösungen in dieser Antwort setzen GNU sed voraus . Wenn Sie FreeBSD oder macOS verwenden, ersetzen Sie -i mit -i '' . Beachten Sie auch, dass die Verwendung des -i wechseln Sie mit einer beliebigen Version von sed hat bestimmte Auswirkungen auf die Dateisystemsicherheit und ist in keinem Skript ratsam, das Sie in irgendeiner Weise verteilen möchten.

  • Nicht rekursiv, Dateien nur in diesem Verzeichnis:

     sed -i -- 's/foo/bar/g' *
     perl -i -pe 's/foo/bar/g' ./* 
    

(die perl einer schlägt fehl für Dateinamen, die mit | enden oder Leerzeichen)).

  • Rekursive, reguläre Dateien (einschließlich versteckter ) in diesem und allen Unterverzeichnissen

     find . -type f -exec sed -i 's/foo/bar/g' {} +
    

    Wenn Sie zsh verwenden:

     sed -i -- 's/foo/bar/g' **/*(D.)
    

    (kann fehlschlagen, wenn die Liste zu groß ist, siehe zargs zu umgehen).

    Bash kann nicht direkt nach regulären Dateien suchen, eine Schleife ist erforderlich (geschweifte Klammern vermeiden das globale Setzen der Optionen):

     ( shopt -s globstar dotglob;
         for file in **; do
             if [[ -f $file ]] && [[ -w $file ]]; then
                 sed -i -- 's/foo/bar/g' "$file"
             fi
         done
     )
    

    Die Dateien werden ausgewählt, wenn sie tatsächliche Dateien sind (-f) und beschreibbar sind (-w).

2. Nur ersetzen, wenn der Dateiname mit einer anderen Zeichenfolge übereinstimmt / eine bestimmte Erweiterung hat / von einem bestimmten Typ ist usw.:

  • Nicht rekursiv, Dateien nur in diesem Verzeichnis:

    sed -i -- 's/foo/bar/g' *baz*    ## all files whose name contains baz
    sed -i -- 's/foo/bar/g' *.baz    ## files ending in .baz
    
  • Rekursive, reguläre Dateien in diesem und allen Unterverzeichnissen

    find . -type f -name "*baz*" -exec sed -i 's/foo/bar/g' {} +
    

    Wenn Sie Bash verwenden (geschweifte Klammern vermeiden das globale Setzen der Optionen):

    ( shopt -s globstar dotglob
        sed -i -- 's/foo/bar/g' **baz*
        sed -i -- 's/foo/bar/g' **.baz
    )
    

    Wenn Sie zsh verwenden:

    sed -i -- 's/foo/bar/g' **/*baz*(D.)
    sed -i -- 's/foo/bar/g' **/*.baz(D.)
    

Der -- dient dazu, sed mitzuteilen dass keine Flags mehr in der Kommandozeile angegeben werden. Dies ist nützlich, um Dateinamen zu schützen, die mit - beginnen .

  • Ist eine Datei von einem bestimmten Typ, beispielsweise ausführbar (siehe man find für weitere Optionen):

    find . -type f -executable -exec sed -i 's/foo/bar/g' {} +
    

zsh :

    sed -i -- 's/foo/bar/g' **/*(D*)

3. Nur ersetzen, wenn der String in einem bestimmten Kontext gefunden wird

  • Ersetzen Sie foo mit bar nur wenn ein baz vorhanden ist später in derselben Zeile:

     sed -i 's/foo(.*baz)/bar1/' file
    

In sed , mit ( ) speichert, was in Klammern steht, und Sie können dann mit 1 darauf zugreifen . Es gibt viele Variationen dieses Themas, um mehr über solche regulären Ausdrücke zu erfahren, siehe hier.

  • Ersetzen Sie foo mit bar nur wenn foo befindet sich in der 3D-Spalte (Feld) der Eingabedatei (unter der Annahme von durch Leerzeichen getrennten Feldern):

     gawk -i inplace '{gsub(/foo/,"baz",$3); print}' file
    

(benötigt gawk 4.1.0 oder neuer).

  • Verwenden Sie für ein anderes Feld einfach $N wobei N ist die Nummer des Interessengebiets. Für ein anderes Feldtrennzeichen (: in diesem Beispiel) verwenden Sie:

     gawk -i inplace -F':' '{gsub(/foo/,"baz",$3);print}' file
    

Eine andere Lösung mit perl :

    perl -i -ane '$F[2]=~s/foo/baz/g; $" = " "; print "@Fn"' foo 

HINWEIS:Sowohl das awk und perl Lösungen wirken sich auf die Abstände in der Datei aus (entfernen Sie die führenden und abschließenden Leerzeichen und wandeln Sie in den übereinstimmenden Zeilen Sequenzen von Leerzeichen in ein Leerzeichen um). Verwenden Sie für ein anderes Feld $F[N-1] wobei N die gewünschte Feldnummer ist und für ein anderes Feldtrennzeichen verwendet wird (der $"=":" setzt das Ausgabefeldtrennzeichen auf : ):

    perl -i -F':' -ane '$F[2]=~s/foo/baz/g; $"=":";print "@F"' foo 
  • Ersetzen Sie foo mit bar nur in der 4. Zeile:

     sed -i '4s/foo/bar/g' file
     gawk -i inplace 'NR==4{gsub(/foo/,"baz")};1' file
     perl -i -pe 's/foo/bar/g if $.==4' file
    

4. Mehrere Ersetzungsoperationen:Ersetzen durch verschiedene Zeichenfolgen

  • Sie können sed kombinieren Befehle:

     sed -i 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
    

Beachten Sie, dass die Reihenfolge wichtig ist (sed 's/foo/bar/g; s/bar/baz/g' ersetzt foo mit baz ).

  • oder Perl-Befehle

     perl -i -pe 's/foo/bar/g; s/baz/zab/g; s/Alice/Joan/g' file
    
  • Wenn Sie eine große Anzahl von Mustern haben, ist es einfacher, Ihre Muster und ihre Ersetzungen in einem sed zu speichern Skriptdatei:

     #! /usr/bin/sed -f
     s/foo/bar/g
     s/baz/zab/g
    
  • Oder, wenn Sie zu viele Musterpaare haben, als dass das obige durchführbar wäre, können Sie Musterpaare aus einer Datei lesen (zwei durch Leerzeichen getrennte Muster, $Muster und $Ersetzung, pro Zeile):

     while read -r pattern replacement; do   
         sed -i "s/$pattern/$replacement/" file
     done < patterns.txt
    
  • Das wird bei langen Listen von Mustern und großen Datendateien ziemlich langsam sein, also möchten Sie vielleicht die Muster lesen und einen sed erstellen Skript von ihnen stattdessen. Im Folgenden wird von einem <Leerzeichen> ausgegangen Trennzeichen trennt eine Liste von MATCH<Leerzeichen>REPLACE Paare, die in der Datei patterns.txt einzeln pro Zeile vorkommen :

     sed 's| *([^ ]*) *([^ ]*).*|s/1/2/g|' <patterns.txt |
     sed -f- ./editfile >outfile
    

Das obige Format ist weitgehend willkürlich und lässt beispielsweise kein <Leerzeichen> zu in einem von MATCH oder ERSETZEN . Die Methode ist jedoch sehr allgemein:im Grunde, wenn Sie einen Ausgabestrom erstellen können, der wie ein sed aussieht script, dann können Sie diesen Stream als sed beziehen Skript durch Angabe von sed ’s-Skriptdatei als - stdin.

  • Sie können mehrere Skripte auf ähnliche Weise kombinieren und verketten:

     SOME_PIPELINE |
     sed -e'#some expression script'  
         -f./script_file -f-          
         -e'#more inline expressions' 
     ./actual_edit_file >./outfile
    

Ein POSIX sed verkettet alle Skripte in der Reihenfolge, in der sie auf der Befehlszeile erscheinen, zu einem. Keines davon muss auf ein n enden ewline.

  • grep kann genauso funktionieren:

     sed -e'#generate a pattern list' <in |
     grep -f- ./grepped_file
    
  • Wenn Sie mit festen Zeichenfolgen als Muster arbeiten, empfiehlt es sich, Metazeichen regulärer Ausdrücke mit Escapezeichen zu versehen . Das geht ganz einfach:

     sed 's/[]$&^*./[]/\&/g
          s| *([^ ]*) *([^ ]*).*|s/1/2/g|
     ' <patterns.txt |
     sed -f- ./editfile >outfile
    

5. Mehrere Ersetzungsoperationen:Ersetzen Sie mehrere Muster durch dieselbe Zeichenfolge

  • Ersetzen Sie foo , bar oder baz mit foobar

     sed -Ei 's/foo|bar|baz/foobar/g' file
    
  • oder

     perl -i -pe 's/foo|bar|baz/foobar/g' file
    

Linux
  1. Wie ersetze ich eine Zeichenfolge durch eine Zeichenfolge, die Slash mit Sed enthält?

  2. Wie kann ich am Anfang jeder Datei in einem Ordner in Bash eine Zeichenfolge hinzufügen?

  3. So ersetzen Sie eine Zeichenfolge in mehreren Dateien in der Linux-Befehlszeile

  4. tr Befehl - wie man die Zeichenfolge \n durch einen tatsächlichen Zeilenumbruch (\n) ersetzt

  5. ersetzt das n-te Vorkommen von String in jeder Zeile einer Textdatei

So verwenden Sie sed zum Suchen und Ersetzen von Zeichenfolgen in Dateien

So finden Sie eine Zeichenfolge in einer Datei unter Linux

Ersetzen von Zeichenfolgen in Bash

So verwenden Sie den SED-Befehl zum Suchen und Ersetzen von Zeichenfolgen in Dateien

So suchen und ersetzen Sie Text, Wort oder Zeichenfolge in einer Datei

So verwenden Sie Sed zum Suchen und Ersetzen einer Zeichenfolge in einer Datei