Was ist der Unterschied zwischen STDIN und an command übergebenen Argumenten?

16

Ich könnte das eine oder andere Formular verwenden, um die catMethode auszuführen :

cat file_name
cat < file_name

Das Ergebnis ist das gleiche

Dann möchte ich manim Format ausführenstdin

man < file_name

While file_nameenthält:

# file_name
cat

Aber es erscheint What manual page do you want?anstatt auszuführen man cat.

Ich möchte wissen, warum ich Argumente catakzeptieren kann, stdinaber mannicht. Und was ist der Unterschied zwischen Kommandozeilenargumenten und stdin?

Steveyang
quelle

Antworten:

21

Ihre Frage hängt eng damit zusammen, wie die von Ihnen verwendete Shell Benutzereingaben in der Befehlszeile analysiert.

Wenn das erste Wort in der Befehlszeile ein Programm ist, das sich in einem speziellen Ordner befindet (meistens definiert durch PATH) und keine Sonderzeichen mehr angegeben werden (abhängig von der verwendeten Shell), werden alle nachfolgenden Wörter, die durch Leerzeichen oder Tabulatoren getrennt sind, übergeben das Programm in einer speziellen Form, dh einem Array. Mit jedem Wort als ein Element im Array.

Wie das aufzurufende Programm die Argumente (im Array) interpretiert, hängt davon ab, wie es programmiert ist. Es gibt einige Quasi-Standards, wie die Syntax der Argumente aussehen sollte, aber im Allgemeinen ist der Programmierer völlig frei. Das erste Argument kann also als Name einer Datei interpretiert werden, oder was auch immer der Programmierer zum Zeitpunkt der Erstellung des Programms dachte.

Im Fall , dass Sie das Sonderzeichen hinzuzufügen <oder >zu der Befehlszeile, die Shell dosn't append <und >noch nachfolgende Worte an das Array , das an das Programm übergeben werden. Mit <or >given beginnt die Shell, ausgefallene Dinge zu machen, die vom zugrunde liegenden Kernel unterstützt werden (Keyword Piping ). Um zu verstehen, was los ist, muss man verstehen, was STDINund STDOUT(da es nicht unmittelbar damit zusammenhängt, lasse ich es aus STDERR).

Alles, was Sie auf Ihrem Terminal sehen (in den meisten Fällen ein Teil Ihrer Anzeige), wird entweder von der Shell oder einem anderen Programm, das Sie zuvor aufgerufen haben, in eine spezielle Datei geschrieben (in Unix ist alles eine Datei ). Diese Datei hat eine spezielle ID und wird aufgerufen STDOUT. Wenn ein Programm Daten von der Tastatur lesen möchte, fragt es die Tastatur nicht direkt ab (zumindest in den meisten Fällen), sondern liest aus einer speziellen Datei namens STDIN. Intern ist diese Datei mit Ihrem Standardeingabegerät verbunden, in den meisten Fällen Ihrer Tastatur.

Wenn die Shell eine geparste Befehlszeile liest <oder >eingibt, manipuliert sie diese für die Zeit, in der das entsprechende Programm ausgeführt wird, STDINoder STDOUTin einer bestimmten Art. STDINund STDOUTzeigen Sie nicht mehr auf das Terminal oder das Standard-Eingabegerät, sondern auf den nachfolgenden Dateinamen in der Befehlszeile.

Im Falle der beiden Zeilen

cat file_name
cat < file_name

Das beobachtete Verhalten ist identisch, da der entsprechende Entwickler die catDaten entweder STDINaus der Datei liest oder aus ihr liest, deren Name als erstes Befehlszeilenargument angegeben wird (das ist das erste Element in dem Array, an das die Shell übergibt cat). Anschließend catschreibt den gesamten Inhalt file_nameoder STDINzum Terminal , da wir die Schale nicht anweisen zu manipulieren zu STDOUT. Denken Sie daran, dass Ihre Shell in der zweiten Zeile so manipuliert STDIN, dass sie nicht mehr auf Ihr Standardeingabegerät, sondern auf eine Datei verweist, die file_namein Ihrem aktuellen Arbeitsverzeichnis aufgerufen wird .

Im anderen Fall der Leitung

man < file_name

mansoll nichts auslesen, STDINwenn es ohne Argument aufgerufen wird, dh ein leeres Array. Also die Leitung

man < file_name

gleich

man

Zum Beispiel manliest auch etwas aus STDIN, wenn Sie -l -an übergeben man. Mit dieser Option in der Befehlszeile können Sie den Inhalt aller manLesevorgänge STDINauf Ihrem Terminal anzeigen . So

man -l - < file_name

würde auch funktionieren (aber sei vorsichtig, manist nicht nur ein Pager, sondern analysiert auch die Eingabe der Datei und so kann der Dateiinhalt und der angezeigte Inhalt abweichen).

So wie STDIN, STDOUTund die Befehlszeilenargumente werden so interpretiert , ist alles an den entsprechenden Entwickler auf.

Ich hoffe meine Antwort konnte die Dinge klären.

user1146332
quelle
Vielen Dank für diese ausführliche Erklärung. In den letzten Absätzen haben Sie die Verwendung man -l - < file_namevon manInterpreten STDINals Argumente erwähnt. In meinem System schlägt dies jedoch fehl STDERR:man -l - < tee man: invalid option -- l man, version 1.6c
steveyang
Bitte. Aber ich habe nicht erwähnt, dass zumindest meine Version von man( man-db ) Argumente STDINmit den angegebenen Argumenten -lgefolgt von liest -. Es interpretiert nur Daten von STDINals Manpage. Ausführlichere Erklärungen zu gültigen Argumenten und deren Interpretation finden Sie auf der Manpage des jeweiligen Programms. In Ihrem Fall konsultieren man man. Vielleicht gibt es eine ähnliche Option für Ihre man. Wenn Sie Befehlszeilenargumente für ein bestimmtes Programm lesen möchten STDIN xargs(wie oben erwähnt), ist dies der richtige Weg.
user1146332
Ich man manund finde die in meinem Betriebssystem unterstützt es nicht. Wie auch immer, danke für diese Erklärung dieser beiden Konzepte für mich.
Steveyang
Ich habe Ihre Antwort so bearbeitet, dass sie tatsächlich nützliche Links anstelle von lmgtfy enthält. Das Posten von lmgtfy-Links ist 1) unhöflich, 2) nicht hilfreich und 3) auf den SE-Sites sehr verpönt . Geben Sie entweder einen Link an oder nicht. Wenn Sie dies jedoch möchten, geben Sie einen Link zu tatsächlichen Informationen an und nicht zu einer sarkastischen Methode, um jemandem zu zeigen, wie er sie findet.
Terdon
12

Sie sind völlig anders. Befehlszeilenargumente werden in einem Array an das Programm übergeben und es kann damit tun, was es will. stdin ist ein Eingabestream, von dem das Programm Daten anfordern muss. Programme, die Dateien verarbeiten, unterstützen häufig beides, müssen dies jedoch manuell tun. Sie überprüfen, ob ein Dateiname als Befehlszeilenargument übergeben wurde, und lesen stattdessen von stdin

Sie scheinen damit zu rechnen man, stdin zu lesen, um die Manpage zu finden, die angezeigt werden soll, was ein wirklich merkwürdiges Verhalten wäre. Wann würdest du das jemals benutzen? Die Tatsache, dass catsein Standard angezeigt wird, ist ein Artefakt der Tatsache, dass es nichts anderes tut; Ich glaube nicht, dass ein anderes Tool so funktioniert. grepKann zum Beispiel einen Dateinamen übernehmen oder lesen stdin, verarbeitet aber die Daten weiter stdin, liest keinen Dateinamen aus stdinund öffnet ihn dann

Wenn Sie dieses Verhalten wirklich benötigen, können Sie Folgendes verwenden xargs, um eine Datei in Befehlszeilenargumente zu konvertieren:

$ xargs man < file_name

Oder binden Sie einfach einen catAnruf in den manAnruf ein:

$ man $(cat file_name)
Michael Mrozek
quelle
In Bash können Sie verwenden man $(<file_name).
Jordanien
Betreff: "Ich denke, kein anderes Tool funktioniert so" - Perls (<>)in einer Schleife wird STDINoder Befehlszeilenargumente als Dateinamen ...
Aaron D. Marasco
@ AaronD.Marasco Ich meinte, kein Tool nimmt ein Argument oder liest einen Dateinamen aus stdin und liest das Argument aus dieser Datei
Michael Mrozek
@MichaelMrozek Danke für diese Klarstellung. Der Zweck, den ich benutzte, man < file_nameist, mir zu helfen, diese zwei Konzepte zu verstehen. Wenn Sie Ihre Erklärung lesen, entscheidet der Befehlsautor über die Implementierung. Also, wenn ich unter Recht, verarbeitet die findnimmt Argumente eher STDIN?
Steveyang