Wie führe ich xargs grep für grep-Ausgaben mit Leerzeichen aus?

8

Ich suche nach Dateien basierend auf einem regulären Ausdruck und versuche dann, diese Dateien nach Inhalten zu durchsuchen. So habe ich zum Beispiel so etwas

#Find all C++ files that match a certain pattern and then search them
find . -name "*.cpp" | grep "<name regex>" | xargs grep "<content regex>"

Das Problem, auf das ich stoße, ist, dass einige der Pfade Leerzeichen enthalten, was verwirrt xargs. Ich weiß, dass ich, wenn ich nur verwenden würde find, das -print0Argument (zusammen mit dem -0Argument on xargs) verwenden könnte, um zu verhindern, dass xargs Leerzeichen als Trennzeichen behandelt. Gibt es etwas ähnliches mit grep?

Oder gehe ich dieses Problem völlig falsch an? Naiv, findum grepfür xargs grepmich Sinn zu machen, aber ich bin offen für andere Ansätze, die die gleichen Ergebnisse liefern.

Quantikel
quelle
2
Sie können Argumente mit positionieren , xargsindem Sie -iParameter, a la cat sample.txt | grep "pat t ern" | xargs -i grep "{}"- die geschweiften Klammern sagen sie , wo das Argument zu positionieren. Das Handbuch sagt mir, dass -ies veraltet ist, -Ialso lohnt es sich vielleicht auch, einen Blick darauf zu werfen.
DougBTV

Antworten:

5

Verwenden Sie so etwas vielleicht (wenn gnu grep).

grep -r 'content pattern' --include==*.cpp

Mann grep

--include = GLOB Durchsucht nur Dateien, deren Basisname mit GLOB übereinstimmt (unter Verwendung des Platzhalterabgleichs wie unter --exclude beschrieben).

Siehe auch die Optionen für Nulltrennzeichen.

-Z, --null Gibt ein Null-Byte (das ASCII-NUL-Zeichen) anstelle des Zeichens aus, das normalerweise einem Dateinamen folgt. Beispielsweise gibt grep -lZ nach jedem Dateinamen anstelle des üblichen Zeilenumbruchs ein Null-Byte aus. Diese Option macht die Ausgabe auch bei Dateinamen mit ungewöhnlichen Zeichen wie Zeilenumbrüchen eindeutig. 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.

-z, --null-data Behandelt die Eingabe als eine Reihe von Zeilen, die jeweils durch ein Null-Byte (das ASCII-NUL-Zeichen) anstelle einer neuen Zeile abgeschlossen werden. Wie die Option -Z oder --null kann diese Option mit Befehlen wie sort -z verwendet werden, um beliebige Dateinamen zu verarbeiten.

Zoredache
quelle
Beachten Sie, dass grep -r include='*.cpp'es sich um einen Shell-Glob handelt - und damit um ein Feature-ausgerichtetes W / find . -name '*.cpp' -exec grep -e 'content_pattern' -- {} \;Nicht-W /find . -name '*.cpp' | grep 'name_pattern' | xargs grep 'content_pattern'
MikeServ
4

Wenn Sie durch viele Reifen springen müssen, geht die Effizienz von xargs trotzdem verloren. Hier ist eine grobe Lösung:

find . -iname "*.cpp" | grep "<pattern>" | while read -r x; do grep exa "$x"; done

Jedes Mal, wenn ich auf Probleme mit Leerzeichen in Dateinamen stoße, lautet die Antwort doppelte Anführungszeichen für eine Variable.

Baazigar
quelle
Dadurch wird der innere Grep der Schleife für jede vom äußeren Grep gefundene Zeile eindeutig ausgeführt. Das ist viel Aufwand.
Adam Katz
3

Verwenden Sie finddiese Option , um alle Dateinamen zu filtern. Eher, als

find . -name "*.cpp" | grep "foo" | xargs grep 

tun

find . -name "*.cpp" -name "*foo*" -print0 | xargs -0 grep 

Wenn Sie etwas etwas komplizierteres tun möchten, wie

find . -name "*.cpp" | egrep "foo|bar" | xargs grep 

du kannst tun

find . -name "*.cpp" "(" -name "*foo*" -o -name "*bar*" ")" -print0 | xargs -0 grep 

Beachten Sie, dass diese auch für Dateien mit Zeilenumbrüchen im Namen funktionieren sollten.

Und wenn Sie die Kraft ausgewachsener regulärer Ausdrücke benötigen, können Sie diese verwenden -regex.

Scott
quelle
2

Dies sollte auch ohne GNU-Tools funktionieren:

#Find all C++ files that match a certain pattern and then search them
find . -name "*.cpp"  | grep "<name regex>" | perl -pe 's/\n/\0/' \
  | xargs -0 grep "<content regex>"

Der perlAufruf ersetzt Zeilenumbrüche durch Nullzeichen, wodurch xargs -0die Eingabe pro Zeile und nicht pro Leerzeichen interpretiert werden kann.

GNU verwenden, können Sie den entfernen perlAnruf und ändern xargs -0 …zuxargs -d "\n" …

Nicht haben perloder GNU? Versuchen Sie es awk '{printf "%s%c", $0, 0}'stattdessen.

Adam Katz
quelle
1
Dies ist möglicherweise nicht das Richtige, wenn einige der Dateinamen Zeilenumbrüche enthalten (ein eher ungewöhnliches Ereignis, sicher, aber nicht unmöglich).
Dhag
@dhag hat einen gültigen Punkt in Bezug auf xargs -d "\n". Dies ist ein sehr ungewöhnliches Ereignis. Wenn Sie jedoch keine Kontrolle über die Daten haben und befürchten, dass dies ein Sicherheitsrisiko darstellt, sollten Sie die Ausgabeerwartungen berücksichtigen.
Adam Katz