Verwenden von sed und grep / egrep zum Suchen und Ersetzen


97

Ich verwende egrep -Rgefolgt von einem regulären Ausdruck, der ungefähr 10 Gewerkschaften enthält, also wie: .jpg | .png | .gifusw. Dies funktioniert gut, jetzt möchte ich alle gefundenen Zeichenfolgen durch ersetzen.bmp

Ich dachte an so etwas

egrep -lR "\.jpg|\.png|\.gif" . | sed "s/some_expression/.jpg/" file_it_came_form

Das Problem hier ist also, wie ich einen ähnlichen regulären Union-Ausdruck in sedmache und wie ich ihm sage, dass er die Änderungen an der Datei speichern soll, von der er die Eingabe erhalten hat.


2
Ich habe diese Frage gefunden, als ich nach Möglichkeiten gesucht habe, mehrere Dateien in einer Verzeichnishierarchie zu suchen und zu ersetzen. Versuchen Sie für andere in meiner Situation rpl .
— Titandecoy

danke rpl funktioniert und ist wirklich leicht zu merken .. nur rpl old_string new_string target_files.
— Cesarpachon

Antworten:


183

Verwenden Sie diesen Befehl:

egrep -lRZ "\.jpg|\.png|\.gif" . \
    | xargs -0 -l sed -i -e 's/\.jpg\|\.gif\|\.png/.bmp/g'
  • egrep: Finden Sie passende Zeilen mit erweiterten regulären Ausdrücken

    • -l: Nur übereinstimmende Dateinamen auflisten

    • -R: Durchsuchen Sie rekursiv alle angegebenen Verzeichnisse

    • -Z: \0als Datensatztrennzeichen verwenden

    • "\.jpg|\.png|\.gif": mit einer der Zeichenfolgen übereinstimmen ".jpg", ".gif"oder".png"

    • .: Starten Sie die Suche im aktuellen Verzeichnis

  • xargs: Führen Sie einen Befehl mit dem Argument stdin aus

    • -0: \0als Datensatztrennzeichen verwenden. Dies ist wichtig , die passen -Zvon egrepund durch Leerzeichen und Zeilenumbrüche in Eingabedateinamen werden getäuscht zu vermeiden.

    • -l: Verwenden Sie eine Zeile pro Befehl als Parameter

  • sed: the s tream ed itor

    • -i: Ersetzen Sie die Eingabedatei durch die Ausgabe, ohne eine Sicherungskopie zu erstellen

    • -e: Verwenden Sie das folgende Argument als Ausdruck

    • 's/\.jpg\|\.gif\|\.png/.bmp/g': Alle Vorkommen der Saiten ersetzen ".jpg", ".gif"oder ".png"mit".bmp"


es funktioniert alles außer dem | im sed Teil. Ich verstehe nicht warum, da es Sinn macht ... der -l Teil von xargs hat mir Fehler gegeben, also habe ich es herausgenommen, könnte das zusammenhängen?
— Ori

Ich habe festgestellt, dass dieser Befehl am Ende aller von ihm verarbeiteten Dateien eine neue Zeile hinzufügt.
— titaniumdecoy

@titanumdecoy: Ich konnte dieses Verhalten nicht reproduzieren. Welche Version von sed haben Sie verwendet und auf welchem ​​Betriebssystem sind Sie?
— David Schmitt

1
@DavidSchmitt: Sie möchten wahrscheinlich sed -rfür erweiterte reguläre Ausdrücke verwenden. Zu diesem Zeitpunkt stimmt das Muster mit dem überein, was in egrep verwendet wird, und Sie können es zur Wiederverwendung in eine Variable einfügen.
— Bukzor

Dieser Befehl ersparte mir stundenlanges Kopieren von Header-Dateien aus meiner App für die von mir erstellte Bibliothek. Das ist großartig :) Hier ist der Befehl, den ich egrep -lRZ "\ .h $" verwendet habe. | xargs -0 tar -cvf headers.tar | (cp headers.tar headers; cd headers; tar xf headers.tar;)
— The Lazy Coder

11

Ehrlich gesagt, so sehr ich Sed für geeignete Aufgaben liebe, ist dies definitiv eine Aufgabe für Perl - es ist wirklich mächtiger für diese Art von Einzeiler, insbesondere, "es dorthin zurückzuschreiben, wo es herkommt" (Perls -iSchalter erledigt es dafür Sie und optional können Sie auch die alte Version beibehalten, z. B. mit einem angehängten .bak, verwenden Sie -i.bakstattdessen einfach ).

perl -i.bak -pe 's/\.jpg|\.png|\.gif/.jpg/

anstatt komplizierte Arbeit in sed (wenn überhaupt möglich) oder awk ...


6
sed verwendet -i, genau wie Perl.
— Stobor

@Stobor - Ich schwöre, ich hatte Probleme, bei denen die Perl-Operation, als ich die Regex-Ersatzzeichenfolge fütterte, genau das tat, was ich wollte, im Gegensatz zu sed, auch wenn ich die Regex-Option gegeben habe sed. Ich glaube, ich habe entweder einige Flags für sed vergessen oder es hatte Einschränkungen.
— Meder Omuraliev

10

Ein anderer Weg, dies zu tun

find . -name *.xml -exec sed -i "s/4.6.0-SNAPSHOT/5.0.0-SNAPSHOT/" {} \;

Hilfe zum obigen Befehl

Die Suche führt die Suche für Sie in dem aktuellen Verzeichnis durch, das durch angegeben ist .

-name Der Name der Datei in meinem Fall, seine pom.xml, kann Platzhalter geben.

-exec ausführen

sed Stream-Editor

-i Fall ignorieren

s ist für Ersatz

/4.6.0.../ Zu durchsuchende Zeichenfolge

/5.0.0.../ Zu ersetzende Zeichenfolge


vielleicht nicht so mächtig - aber das ist für mich viel einfacher zu verstehen als die akzeptierte Antwort
— icc97

5

Ich konnte keinen der Befehle auf dieser Seite für mich verwenden: Die sed-Lösung fügte am Ende aller verarbeiteten Dateien eine neue Zeile hinzu, und die perl-Lösung konnte nicht genügend Argumente von find akzeptieren. Ich habe diese Lösung gefunden, die perfekt funktioniert:

find . -type f -name '*.[hm]' -print0 
    | xargs -0 perl -pi -e 's/search_regex/replacement_string/g'

Dadurch wird den aktuellen Verzeichnisbaum und ersetzt rekursiv search_regexmit replacement_stringin beliebigen Dateien mit der Endung .hoder .m.

Ich habe in der Vergangenheit auch rpl für diesen Zweck verwendet.


0

Versuchen Sie etwas mit einer for-Schleife

 for i in `egrep -lR "YOURSEARCH" .` ; do echo  $i; sed 's/f/k/' <$i >/tmp/`basename $i`; mv /tmp/`basename $i` $i; done

nicht schön, sollte aber tun.


3
xargs ist hier definitiv besser geeignet.
— Nathan Fellman

1
und die Verwendung des |while read iMusters würde Streaming ermöglichen und Längenbeschränkungen vermeiden, wenn die Ergebnisse von egrep zu lang werden
— David Schmitt

0

Mein Anwendungsfall war ich ersetzen wollte foo:/Drive_Lettermit foo:/bar/baz/xyz konnte ich tun , um es mit dem folgenden Code in meinem Fall. Ich befand mich in demselben Verzeichnis, in dem sich die meisten Dateien befanden.

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

hoffe das hat geholfen.

UPDATE s | foo: / Drive_letter: | foo: / ba / baz / xyz | g


Sie können andere Begrenzer für den Befehl sed verwenden, und dies macht Pfadnamen viel schöner:sed 's|foo:/Drive_letter:|foo:/ba/baz/xyz|g'
— Kevin
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.