Wie kann die Ausgabe von grep sicher in einem Skript verwendet werden?

Wie kann die Ausgabe von grep sicher in einem Skript verwendet werden?

In einem Skript möchte ich Dateien finden, die Text enthalten. Ich muss wissen, in welcher Datei sich der Text befindet und in welcher Zeile der Text in der Datei vollständig enthalten ist. grepist das Dienstprogramm, das dies tut, aber wie kann ich die Ausgabe in eine nutzbare Form bringen, wenn man bedenkt, dass sie in Dateinamen enthalten sein kann :? Gibt es dafür eine Art --porcelainModus grep, den ich verwenden kann, ähnlich wie gitBefehle ihn oft haben?

Beispiel: Ich habe einen Ordner voller Dateien mit test-num:1:date:jan-2diesem Namen, den ich durchsuchen möchte. Die Dateien enthalten (unter anderem) FAILURE:<some reason>oder SUCCESS:<some reason>. Ich brauche ein Skript, das nach bestimmten Gründen sucht und den Namen der Datei und den Grund (die ganze Textzeile reicht aus) für die spätere Verarbeitung speichert. Die Ausgabe kann in jeder beliebigen Datenstruktur erfolgen, solange ich Code darüber ausführen kann.

Antwort1

So etwas wie ein gibt es nicht grep --porcelain, die Behandlung von Sonderzeichen in Dateinamen war unter UNIX immer eine Nebensache. Sie könnten es auf Kosten der Effizienz mit etwas wie dem Folgenden versuchen:

pattern='some pattern'
for file in ./*; do
    grep -- "$pattern" "$file" | while read -r line; do
        printf 'file: %s, line: %s\n' "$file" "$line"
    done
done

Antwort2

Neuere (oder ähnliche) Versionen von GNU grep haben eine Option -Z, die die Ausgabe eindeutig macht, aber sie ist hauptsächlich für Anwendungen wie gedacht grep -lZ … | xargs -0. Sie funktioniert immer noch, wenn Sie Zeileninhalte auflisten, das Nullbyte ersetzt den Doppelpunkt und der Zeileninhalt endet immer noch mit einem Zeilenumbruch¹, aber Shells können nicht gut mit Nullbytes umgehen, sodass Sie beim Parsen dieser Ausgabe Schwierigkeiten haben werden.

Eine einfache Lösung (mit leichten Leistungseinbußen) besteht darin, grep für jede Datei einzeln auszuführen.

Eine andere Lösung besteht darin, eine Sprache wie Perl oder Python zu verwenden. Perl kann grep ziemlich gut emulieren;  grep REGEXist im Grunde perl -ne '/REGEXP/ and print'.

Aber Sie brauchen das vielleicht gar nicht, wenn die Ausgabe nicht wirklich mehrdeutig ist. Wenn die übereinstimmenden Zeilen beispielsweise keine Doppelpunkte enthalten, dann ist der Dateiname alles in einer Zeile bis zum letzten Doppelpunkt. Wenn die übereinstimmenden Zeilen alle mit SUCCESSoder beginnen FAILUREund diese Wörter nicht in Dateinamen vorkommen, können Sie dies verwenden, um die Trennung usw. zu lokalisieren.

¹ Außer wenn -zzum Filtern von nullterminierten Datensätzen anstelle von durch eine neue Zeile beendeten Datensätzen null verwendet wird, ist null sowohl das Dateinamen-Abschlusszeichen als auch das Ergebnis-Abschlusszeichen. Ohne -oist die Ausgabe immer noch eindeutig, wobei abwechselnd die Ausgabedatensätze Dateinamen und die Datensätze in der Ausgabe übereinstimmen.

Antwort3

So verwenden Sie die Ausgabe von grep sicherin einem Skript?

... Die Ausgabe kann in jeder beliebigen Form erfolgenDatenstruktur,solange ich Code darüber ausführen kann.

Shell-Skripte haben eigentlich keine Datenstrukturen. Es gibt Arrays, aber das ist auch schon alles – und es ist nicht einfach, per Pipe weitergeleitete Ausgaben sicher in ein Array zu übertragen. (DateinamendürfenZeilenumbrüche enthalten.)

Der beste Weg umCode ausführenüber Ihre Dateien in einem Shell-Skript besteht darin, den Code einfach über die Dateien auszuführen – und nicht zu versuchen, die Dateinamen für die spätere Verwendung zu speichern.

Verwenden Sie dazu find:

find somedir -type f -exec grep -q somepattern {} \; -exec somecommand {} \;

Wenn man Ihre Frage jedoch genauer liest, sieht es so aus, als ob Sie das eigentlich nicht wollen.Code ausführenüber Ihre Dateien, Sie möchten nur eine Textverarbeitung für bestimmte Zeilen durchführen. In diesem Fall -zist die GNU Grep-Option wahrscheinlich das, was Sie wollen. Damit und mit Kenntnissen in Sed oder Awk wird Ihre Frage beantwortet.


Es könnte sinnvoll sein, Ihre Dateibenennungskonvention zu ändern.

verwandte Informationen