Ich kenne den grep
Befehl und lerne die Funktionen von kennen xargs
. Ich lese diese Seite durch, die einige Beispiele für die Verwendung des xargs
Befehls enthält.
Das letzte Beispiel, Beispiel 10, verwirrt mich. Es besagt: "Der Befehl xargs führt den Befehl grep aus, um alle Dateien (unter den vom Befehl find bereitgestellten Dateien) zu finden, die die Zeichenfolge 'stdlib.h' enthielten."
$ find . -name '*.c' | xargs grep 'stdlib.h'
./tgsthreads.c:#include
./valgrind.c:#include
./direntry.c:#include
./xvirus.c:#include
./temp.c:#include
...
...
...
Was ist jedoch der Unterschied zur einfachen Verwendung
$ find . -name '*.c' | grep 'stdlib.h'
?
Offensichtlich kämpfe ich immer noch mit dem, was Xargs genau macht, also ist jede Hilfe dankbar!
command-line
grep
xargs
Alpha Omega
quelle
quelle
Antworten:
Dies leitet die Ausgabe (stdout) * von
find
(stdin von) *grep 'stdlib.h'
als Text weiter (dh die Dateinamen werden als Text behandelt).grep
macht seine übliche Sache und findet die passenden Zeilen in diesem Text (alle Dateinamen, die selbst das Muster enthalten). Der Inhalt der Dateien wird niemals gelesen.Diese erstellt einen Befehl
grep 'stdlib.h'
zu dem jedes Ergebnisfind
ist ein Argument - so ist dies für die Spiele aussehen wird innerhalb jeder Datei gefundenfind
(xargs
kann seine stdin in Argumente an die gegebenen Befehle wie das Drehen gedacht werden) *Verwenden Sie
-type f
in Ihrem Befehl find, oder es werden Fehlergrep
für übereinstimmende Verzeichnisse angezeigt. Auch wenn die Dateinamen Leerzeichen enthalten,xargs
wird vermasseln schlecht, so verwenden Sie die Null - Separator durch Zugabe-print0
undxargs -0
für zuverlässigere Ergebnisse:* fügte diese zusätzlichen erklärenden Punkte hinzu, wie im Kommentar von @cat vorgeschlagen
quelle
|
Rohre stdout zu grep stdin , die nicht das gleiche wie grep Argumente und gibt verwirrende Ergebnisse.find -name '*.c' -exec grep stdlib.h {} +
. Ich benutze so ziemlich nie Xargs. Ebenfalls überrascht erwähnte niemand, dass Xargs einem ähnlichen Zweck dient,grep $(find)
um Substitution zu befehlen, also schrieb ich eine eigene Antwort. Xargs als Befehlsersetzung mit weniger Einschränkungen und Problemen zu erklären, erscheint natürlich.find -delete
für diesen speziellen Fall? Oder für andere Befehle alsrm
, wenn Sie GNU find haben,-exec some_command {} +
gruppieren Sie sie in Gruppen wie xargs, stattdessen wird das\;
Verhalten beim Ausführen des Befehls für jeden getrennt.find
führt den Befehl für jede Datei nur dann aus, wenn-exec command \;
Both verwendet wird,xargs
und-exec command \+
ruft den Befehl mit der vom System maximal zulässigen Anzahl von Argumenten auf. Mit anderen Worten, sie sind gleichwertigxargs nimmt seine Standardeingabe und wandelt sie in Befehlszeilenargumente um.
find . -name '*.c' | xargs grep 'stdlib.h'
ist sehr ähnlich zuUnd liefert die gleichen Ergebnisse, solange die Liste der Dateinamen für eine einzelne Befehlszeile nicht zu lang ist. (Linux unterstützt Megabyte Text in einer einzigen Befehlszeile, daher benötigen Sie normalerweise keine xargs.)
Aber beide sind zum Kotzen, weil sie kaputt gehen, wenn Ihre Dateinamen Leerzeichen enthalten . Stattdessen
find -print0 | xargs -0
funktioniert, aber es funktioniert auchDas leitet die Dateinamen niemals irgendwo weiter:
find
Stapelt sie in eine große Befehlszeile und wirdgrep
direkt ausgeführt.\;
stattdessen wird+
grep für jede Datei separat ausgeführt, was viel langsamer ist. Tu das nicht. Da+
es sich jedoch um eine GNU-Erweiterung handelt, müssenxargs
Sie dies effizient tun, wenn Sie nicht davon ausgehen können, dass GNU dies findet.Wenn Sie weglassen,
xargs
wirdfind | grep
das Muster mit der Liste der zu druckenden Dateinamenfind
abgeglichen.An diesem Punkt könnten Sie es genauso gut tun
find -name stdlib.h
. Natürlich erhalten-name '*.c' -name stdlib.h
Sie mit keine Ausgabe, da diese Muster nicht beide übereinstimmen können und Find standardmäßig UND die Regeln zusammen verwendet.Ersetzen Sie
less
zu jedem Zeitpunkt des Prozesses, um zu sehen, welche Ausgabe ein Teil der Pipeline erzeugt.Lesen Sie weiter: http://mywiki.wooledge.org/BashFAQ hat einige großartige Sachen.
quelle
-d
das Trennzeichen setzen, damit Sie-d'\n'
mit einer durch Zeilenumbrüche getrennten Liste umgehen können. Dies kann nützlich sein, wenn Sie eine Liste von Dateinamen in einer Datei usw. behandeln (sofern die Dateinamen keine haben) Zeilenumbrüche in ihnen, das heißt.)myfunc(){ local IFS=$'\n'; fgrep
stdlib.h` $ (find); }
funktioniert ebenfalls mit dem gleichen Effekt. Als(IFS=...; cmd...)
Einzeiler kann eine Subshell auch die Änderung an IFS enthalten, ohne dass diese gespeichert / wiederhergestellt werden muss.command $( find )
Sachen. Problematische Dateinamen mit Leerzeichen und Sonderzeichen können diese Art von Dingen beschädigen. Zumindest doppelte Anführungszeichen der Befehlsersetzung.IFS
so einstelle, dass es der Verwendung entsprichtxargs '-d\n'
. Glob-Erweiterung und Verarbeitung von Shell-Metazeichen erfolgen vor den Auswirkungen der Befehlssubstitution. Ich denke, dass dies auch bei Dateinamen mit$()
oder sicher ist>
. Einverstanden, dass die Verwendung der Wortteilung bei der Befehlsersetzung keine bewährte Methode ist, außer für die einmalige interaktive Verwendung, bei der Sie etwas über die Dateinamen wissen.command "$(find)"
Ist aber nur dann sinnvoll, wenn Sie genau 1 Dateinamen erwarten ...Wird im Allgemeinen
xargs
für Fälle verwendet, in denen Sie (mit dem Symbol|
) etwas von einem Befehl zum anderen (Command1 | Command2
) weiterleiten würden, die Ausgabe des ersten Befehls jedoch nicht korrekt als Eingabe für den zweiten Befehl empfangen wird.Dies ist normalerweise der Fall, wenn der zweite Befehl die Dateneingabe über Standard In (stdin) nicht korrekt verarbeitet (z. B .: Mehrere Zeilen als Eingabe, die Art der Zeileneinrichtung, die als Eingabe verwendeten Zeichen, mehrere Parameter als Eingabe, der als empfangene Datentyp) Eingabe usw ..). Um Ihnen ein kurzes Beispiel zu geben, testen Sie Folgendes:
Beispiel 1:
ls | echo
- Dies wird nichts bewirken, da erecho
nicht weiß, wie er mit den empfangenen Eingaben umgeht. In diesem Fallxargs
wird die Eingabe in diesem Fall so verarbeitet, dass sie korrekt verarbeitet werden kannecho
(z. B .: als einzelne Informationszeile).ls | xargs echo
- Dadurch werden alle Informationenls
in einer einzigen Zeile ausgegebenBeispiel 2:
Angenommen, ich habe mehrere goLang-Dateien in einem Ordner namens go. Ich würde sie mit so etwas suchen:
find go -name *.go -type f | echo
- Aber wenn das Pipe-Symbol da und dasecho
am Ende wäre, würde es nicht funktionieren.find go -name *.go -type f | xargs echo
- Hier würde es dank funktionieren,xargs
aber wenn ich jede Antwort vomfind
Befehl in einer einzigen Zeile haben möchte, würde ich Folgendes tun:find go -name *.go -type f | xargs -0 echo
- In diesem Fall wird die gleiche Ausgabe vonfind
mit angezeigtecho
.Befehle wie
cp, echo, rm, less
und andere, die einen besseren Umgang mit der Eingabe benötigen, erhalten einen Vorteil, wenn sie mit verwendet werdenxargs
.quelle
xargs
wird zum automatischen Generieren von Befehlszeilenargumenten verwendet, die (normalerweise) auf einer Liste von Dateien basieren.Überlegen Sie sich also einige Alternativen zur Verwendung des folgenden
xargs
Befehls:Es gibt mehrere Gründe, es anstelle anderer Optionen zu verwenden, die ursprünglich in anderen Antworten nicht erwähnt wurden:
find . -name '*.c' -exec grep 'stdlib.h' {}\;
grep
Für jede Datei wird ein Prozess generiert - dies wird im Allgemeinen als schlechte Vorgehensweise angesehen und kann das System stark belasten, wenn viele Dateien gefunden werden.grep 'stdlib.h' $(find . -name '*.c')
Befehl wahrscheinlich fehl, da die Ausgabe der$(...)
Operation die maximale Befehlszeilenlänge der Shell überschreitetWie in anderen Antworten erwähnt, ist der Grund für die Verwendung des
-print0
Arguments fürfind
dieses Szenario und des-0
Arguments für xargs, dass Dateinamen mit bestimmten Zeichen (z. B. Anführungszeichen, Leerzeichen oder sogar Zeilenumbrüche) weiterhin korrekt behandelt werden.quelle