it-swarm.com.de

Gibt es ein grep-Äquivalent für find -print0 und xargs -0-Schalter?

Ich möchte häufig Befehle wie diese schreiben (in zsh, falls relevant):

find <somebasedirectory> | \
    grep stringinfilenamesIwant | \
    grep -v stringinfilesnamesIdont | \
    xargs dosomecommand

(oder komplexere Kombinationen von Greps)

In den letzten Jahren hat find den -print0-Schalter hinzugefügt, und xargs hat -0 hinzugefügt, mit dem Dateien mit Leerzeichen im Namen elegant behandelt werden können, indem Dateinamen mit Nullen beendet werden.

find <somebasedirectory> -print0 | xargs -0 dosomecommand

grep (zumindest die Version, die ich habe, GNU grep 2.10 auf Ubuntu), scheint jedoch kein Äquivalent zu haben, zu verbrauchen und erzeugt nullterminierte Zeilen. Es hat --null, aber das scheint nur mit der Verwendung von -l zu tun, um Namen auszugeben, wenn Dateien direkt mit grep durchsucht werden.

Gibt es eine gleichwertige Option oder Kombination von Optionen, die ich mit grep verwenden kann? Gibt es alternativ eine einfache und elegante Möglichkeit, meine Befehlszeile einfach mit -regex von find oder vielleicht mit Perl auszudrücken?

38
Andrew Ferrier

Verwenden Sie GNU Grep --null-Flag

Entsprechend der GNU - Grep-Dokumentation können Sie die Ausgabezeilenpräfixsteuerung verwenden, um ASCII -NUL-Zeichen auf dieselbe Weise wie find und xargs zu behandeln.

-Z
--Null
Geben Sie ein Null-Byte (das Zeichen ASCII NUL) anstelle des Zeichens aus, das normalerweise auf einen Dateinamen folgt. Zum Beispiel gibt 'grep -lZ' nach jedem Dateinamen ein Null-Byte anstelle des üblichen Zeilenvorschubs aus. Diese Option macht die Ausgabe eindeutig, selbst wenn Dateinamen ungewöhnliche Zeichen wie Zeilenumbrüche enthalten. Diese Option kann mit Befehlen wie „find -print0“, „Perl -0“, „sort -z“ und „xargs -0“ verwendet werden, um beliebige Dateinamen zu verarbeiten, auch solche, die Zeilenumbrüche enthalten.

Verwenden Sie tr aus GNU Coreutils

Wie das OP korrekt feststellt, ist dieses Flag besonders nützlich, wenn Dateinamen bei der Eingabe oder Ausgabe behandelt werden. Um die grep-Ausgabe tatsächlich in NUL-Zeichen als Zeilenende umzuwandeln, müssen Sie ein Werkzeug wie sed oder tr verwenden, um jede Ausgabezeile zu transformieren. Zum Beispiel:

find /etc/passwd -print0 |
    xargs -0 egrep -Z 'root|www' |
    tr "\n" "\0" |
    xargs -0 -n1

Diese Pipeline verwendet NULs, um Dateinamen von find zu trennen, und konvertiert dann Zeilenumbrüche in NULs in den von egrep zurückgegebenen Zeichenfolgen. Dadurch werden NUL-terminierte Zeichenfolgen an den nächsten Befehl in der Pipeline übergeben. In diesem Fall handelt es sich lediglich um xargs, wodurch die Ausgabe wieder in normale Zeichenfolgen umgewandelt wird. Es kann jedoch auch alles sein, was Sie möchten.

42
Todd A. Jacobs

Da Sie bereits GNU find verwenden, können Sie anstelle der grep die internen Matching-Funktionen für reguläre Ausdrücke verwenden. Beispiel: 

find <somebasedirectory> -regex ".*stringinfilenamesIwant.*" ! -regex ".*stringinfilesnamesIdont.*" -exec dosomecommand {} + 
5
jlliagre

Die neueste Version der GNU grep-Quelle kann jetzt -z/--null verwenden, um die Ausgabe durch Nullzeichen zu trennen, während sie bisher nur in Verbindung mit -l arbeitete: 

http://git.savannah.gnu.org/cgit/grep.git/commit/?id=cce2fd5520bba35cf9b264de2f1b6131304f19d2

Dies bedeutet, dass Ihr Problem automatisch gelöst wird, wenn Sie die neueste Version verwenden.

3

Anstelle einer Pipe können Sie den -exec von find mit dem +-Terminator verwenden. Um mehrere Befehle miteinander zu verketten, können Sie in -exec eine Shell erzeugen.

find ./ -type f -exec bash -c 'grep "[email protected]" | grep -v something | xargs dosomething' -- {} +
2
jordanm

Benutzen

find <somebasedirectory> -print0 | \
 grep -z stringinfilenamesIwant | \
 grep -zv stringinfilesnamesIdont | \
 xargs -0 dosomecommand

Das Muster darf jedoch keine Zeilenumbrüche enthalten, siehe Fehlerbericht .

0
jarno