Wie leite ich die Befehlsausgabe an andere Befehle weiter?

83

Beispiel:

ls | echodruckt nichts (eigentlich eine Leerzeile). Ich würde erwarten, dass es eine Liste von Dateien druckt.

ls | grep 'foo'Funktioniert dagegen wie erwartet (druckt Dateien mit 'foo' im Namen).

Was ich in diesen Situationen mache, ist ungefähr so: ls | while read OUT; do echo $OUT; doneaber das ist ziemlich umständlich.

Warum funktioniert Piping mit einigen Befehlen, aber nicht mit anderen? Wie kann ich dieses Problem umgehen?

Mihai Rotaru
quelle
2
Was erwartest du ls | echozu tun? warum nicht einfach rennen ls?
Theomega
12
Ich habe das einfachste Beispiel verwendet, das meinen Standpunkt verdeutlicht. Dieses Problem trat tatsächlich auf, als ich versuchte, einen Einzeiler zu erstellen, der Git-Objekte im Objektspeicher und deren Typ anzeigt. Also habe ich Objekt-IDs an weitergeleitet git cat-file, aber es hat einfach nicht funktioniert. Anscheinend hat Echo das gleiche Verhalten, also habe ich es als Beispiel genommen.
Mihai Rotaru
Schauen Sie sich auch den Befehl -n für xargs an, der angibt, wie viele Argumente für den Unterbefehl verwendet werden sollen. `... | xargs -n1 git cat-file`
Rich Homolka

Antworten:

118

Es wird zwischen Befehlszeilenargumenten und Standardeingaben unterschieden. Eine Pipe verbindet die Standardausgabe eines Prozesses mit der Standardeingabe eines anderen. Damit

ls | echo

Verbindet den Standardausgang von ls mit dem Standardeingang von Echo. Gut, oder? Nun, echo ignoriert die Standardeingabe und gibt seine Befehlszeilenargumente - in diesem Fall keine für - seine eigene Standardausgabe aus. Die Ausgabe: gar nichts.

In diesem Fall gibt es einige Lösungen. Eine Möglichkeit besteht darin, einen Befehl zu verwenden, der stdin liest und stdout ausgibt, z. B. cat.

ls | cat

Wird "funktionieren", abhängig von Ihrer Definition der Arbeit.

Aber was ist mit dem allgemeinen Fall? Was Sie wirklich wollen, ist die Konvertierung von stdout eines Befehls in Befehlszeilenargumente eines anderen. Wie andere gesagt haben, xargsist das kanonische Hilfsprogramm in diesem Fall das Lesen der Befehlszeilenargumente für einen Befehl aus der Standardeingabe und das Erstellen der auszuführenden Befehle.

ls | xargs echo

Sie können dies auch mit dem Substitutionsbefehl umwandeln $()

echo $(ls)

Würde auch machen was du willst.

Diese beiden Tools sind ziemlich grundlegend für die Skripterstellung in der Shell. Sie sollten beide lernen.

Der Vollständigkeit halber ist, wie Sie in der Frage angeben, die andere grundlegende Möglichkeit, stdin in Befehlszeilenargumente zu konvertieren, der integrierte Befehl der Shell read. Es konvertiert "Wörter" (Wörter, wie durch die IFSVariable definiert ) in eine temporäre Variable, die Sie in allen Befehlsläufen verwenden können.

Reiche Homolka
quelle
1
Eine sehr hilfreiche und informative Antwort, danke! Ich lerne gerade Bash, und ich habe beide xargs und die $ (*) -Notation zuvor gesehen, habe ihnen aber nicht viel Aufmerksamkeit geschenkt. Jetzt weiß ich, wie wichtig sie sind und werde sie auf jeden Fall untersuchen.
Mihai Rotaru
1
xargs war vielleicht das, wonach OP gesucht hat.
Iktys
19

ls | echodruckt nur eine leere Zeile, da echokeine Eingabe gelesen wird; Der letzte Befehl der Pipeline ist, echodass nichts als eine leere Zeile ausgegeben wird.

Allgemein:

a | b

stellt sicher, dass der Ausgang von azum Eingang von wird b. Ich empfehle Ihnen, den PipelinesAbschnitt von zu lesen man bash.


Wenn Sie wirklich lsund echozusammen verwenden möchten, hier einige (ziemlich nutzlose) Beispiele:

ls | xargs -L 1 echo
echo `ls`
for i in `ls` ; do echo $i ; done
cYrus
quelle
11

Wenn Sie echoden lsBefehl ausführen möchten, versuchen Sie Folgendes:

ls | xargs echo

Dies wird echomit der Ausgabe von aufrufen ls.

Nathan Fellman
quelle
3
Oder ls | xargs -I {} echo {}wenn Sie möchten, dass es für jede Zeile einzeln aufgerufen wird
Alex Abdugafarov
3

Warum nicht einfach benutzen:

echo `ls`

Oder viel sicherer:

echo "`ls -lrt`"
Urbwzrd
quelle
4
Oder auch nur echo *.
Kazark