Verstehen, wie Eingaben an Pipes in Bash gesendet werden

17

Ich verstehe nicht ganz, wie Pipes in Bash funktionieren.

Ich weiß, dass es eine Ausgabe von einem Befehl als Eingabe in einem anderen Befehl nimmt.

Was für eine Ausgabe ich bekommen kann, weil es das ist, was der Befehl auf dem Bildschirm ausgibt.

Aber woher weiß ich, welche Eingabe ein Befehl benötigt?

Hier ist ein Beispiel, von dem ich dachte, dass es funktionieren würde:

which gem | rm

Leider nicht.

Welcher Edelstein druckt das /usr/bin/gemso aus, muss die Ausgabe stimmen?

Ich dachte, das wurde mir gegeben, also wäre es so, rm /usr/bin/gemaber ich habe mich geirrt.

Meine Frage ist also, woher weiß ich, welche Eingabe ein Befehl benötigt?

ajsie
quelle
2
Abgesehen von allem anderen rm /usr/bin/gemist es eine schreckliche Idee. Lassen Sie das gem(und den Ruby-Interpreter, zu dem es gehört) in Ruhe und installieren Sie Ihren bevorzugten Ruby-Interpreter (und gem) mit rvm: rvm.beginrescueend.com
Telemachus

Antworten:

23

"Eingabe" und "Befehlszeilenargumente" sind verschiedene Dinge.

rm Entfernt die als Argumente angegebenen Dateien.

Eine Pipe leitet die Ausgabe des linken Befehls an die Eingabe des rechten Befehls um. Dies hat keine Auswirkungen auf die Befehlszeilenargumente des Programms auf der rechten Seite.

Versuchen Sie dazu xargs, die Standardeingabe in Befehlszeilenargumente für die Ausführung eines Programms zu konvertieren. Das ist seine Aufgabe.

which gem | xargs rmZum Beispiel wird das gemin Ihrem PFAD entfernt.

Borealid
quelle
12

rmnimmt keine Eingabe, sondern Argumente. Diese sind unterschiedlich. Argumente sind die Schalter und Dateinamen usw., die Sie einem Programm in der Befehlszeile geben, um sein Verhalten zu beeinflussen. Eingabe sind die Daten, mit denen das Programm arbeitet. Nimmt zum Beispiel grepsowohl Eingaben als auch Argumente an:

grep "foo" file.txt

Es gibt zwei Argumente "foo"und file.txt. Die Eingabe ist der Inhalt von file.txt, nicht die Zeichenfolge file.txtselbst. Da grep Eingaben akzeptiert, können Sie es mit Pipes verwenden:

cat file.txt | grep "foo"

erzeugt die gleiche Ausgabe, da cat file.txtals Argument nimmt und den Inhalt von file.txtals Ausgabe erzeugt. Diese Ausgabe wird dann an grep weitergeleitet, was den gleichen Effekt ergibt, als hätte grep die Datei selbst geöffnet, wie im ersten Beispiel.

Wenn Sie die Ausgabe eines Programms als Argument für ein anderes verwenden möchten, verwenden Sie Backticks:

rm `which gem`

oder diese alternative (bash-spezifische) Syntax:

rm $(which gem)

Bearbeiten: oder xargswie ein anderer Antwortender darauf hinweist. Viele Möglichkeiten, eine Katze mit einer Befehlszeile zu häuten.

Tyler McHenry
quelle
Es ist erwähnenswert, dass cat file.txt | grep "foo"dies hunderte Male langsamer sein kann als grep "foo" file.txt.
Borealid
1
Das ist der Teil, den ich nicht bekomme. Woher weiß ich, was ist ein Argument und was ist die Standardeingabe?
Ajsie
8
@ajsie: Wenn Sie es nach dem Programmnamen und vor dem Drücken der Eingabetaste eingeben, handelt es sich um ein Argument. Wenn Sie es nach dem Start in das Programm eingeben, wird es standardmäßig eingegeben.
Borealid
1
Ich habs! Das erklärte alles. Jetzt weiß ich, dass ich den Befehl sowohl direkt verwenden kann als auch sehen kann, ob er mich auffordert (grep), und ich kann auch das Handbuch lesen (man grep), um zu sehen, ob er die Standardeingabe verwendet.
Ajsie
@ajsie: Wenn Sie nicht in die Manpage eintauchen möchten, gibt es auch grep --helpeinen schnellen Überblick über die akzeptierten Argumente.
Borealid
3

Schauen Sie sich die manSeiten der Befehle an, an denen Sie interessiert sind. Diese Programme geben an, dass sie gelesen haben stdin(versuchen Sie es man grepmit einem beliebten Befehl, der stdin liest).

Fingerhut
quelle
Ich habe versucht man grep | grep 'standard input'und If no file arguments are specified, the standard input is used.als letztes Match bekommen. 👍 Ich musste grepeinen kleinen Vorgeschmack auf seine eigene Medizin geben. 😎
ma11hew28
2

Diese sind alle gefährlich, wenn Sie ein Verzeichnis in Ihrem PATH haben, das Leerzeichen enthält, oder wenn der Befehlsname Leerzeichen enthält:

rm `which gem`       # Dangerous
rm $(which gem)      # Dangerous
which gem | xargs rm # Dangerous

GNU Parallel http: // www.gnu.org/software/parallel/ hat dieses Problem nicht, so dass dies auch dann funktioniert, wenn Sie ein Verzeichnis in Ihrem PATH haben, das Leerzeichen enthält, oder wenn der Befehlsname Leerzeichen enthält:

which gem | parallel rm
parallel -a <(which bass) rm

Sehen Sie sich das Einführungsvideo zu GNU Parallel an: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ole Tange
quelle