Quelle est la différence entre STDIN et les arguments passés à la commande?

16

Je pourrais utiliser l'un ou l'autre formulaire pour exécuter la catméthode:

cat file_name
cat < file_name

le résultat est le même

Ensuite, je veux exécuter manau formatstdin

man < file_name

Alors que file_namecontient:

# file_name
cat

Mais il apparaît au What manual page do you want?lieu d'exécuterman cat .

Je veux savoir pourquoi catpourrait accepter stdincomme arguments mais manne le peut pas. Et quelle est la différence entre les arguments de ligne de commande et stdin?

steveyang
la source

Réponses:

21

Votre question est étroitement liée à la façon dont le shell que vous utilisez analyse les entrées utilisateur sur la ligne de commande.

Si le premier mot de la ligne de commande est un programme, situé dans un dossier spécial (principalement défini par PATH ) et qu'aucun autre caractère spécial n'est donné (en fonction du shell que vous utilisez), tous les mots suivants séparés par des espaces ou des tabulations sont passés à le programme sous une forme spéciale, à savoir un tableau. Avec chaque mot comme un élément du tableau.

La façon dont le programme que vous allez invoquer interprète les arguments (situés dans le tableau) dépend de la façon dont il est programmé. Il y a des quasi normes sur la façon dont la syntaxe des arguments devrait ressembler, mais en général le programmeur est entièrement libre. Ainsi, le premier argument peut être interprété comme le nom d'un fichier ou quoi que pense le programmeur au moment où il a écrit le programme.

Dans le cas où vous ajoutez le caractère spécial <ou >à votre ligne de commande, le shell ne s'ajoute pas <et >ni les mots suivants au tableau qui seront passés au programme. Avec <ou >étant donné le shell commence à faire des choses fantaisistes, supporté par le noyau sous-jacent (mot-clé piping ). Pour comprendre ce qui se passe, vous devez comprendre quoi STDINet STDOUT(comme ce n'est pas immédiatement lié, j'ometSTDERR ) sont.

Tout ce que vous voyez sur votre terminal (dans la plupart des cas une partie de votre affichage) est écrit par le shell ou tout autre programme que vous avez appelé précédemment dans un fichier spécial (sous Unix, tout est un fichier ). Ce fichier a un identifiant spécial et est appelé STDOUT. Si un programme veut lire des données à partir du clavier, il n'interroge pas directement le clavier (au moins dans la plupart des cas) mais lit à partir d'un fichier spécial appelé STDIN. En interne, ce fichier est connecté à votre périphérique d'entrée standard, votre clavier dans la plupart des cas.

Si le shell lit <ou >dans une ligne de commande analysée, il manipule STDINou STDOUTdans un type particulier pendant la durée d'exécution du programme correspondant. STDINet STDOUTne pointe plus vers le terminal ou le périphérique d'entrée standard, mais plutôt vers le nom de fichier suivant sur la ligne de commande.

Dans le cas des deux lignes

cat file_name
cat < file_name

le comportement observé est identique car le développeur correspondant fait catpour lire STDINou lire les données du fichier, dont le nom est donné comme premier argument de ligne de commande (qui est le premier élément du tableau vers lequel le shell passe cat). Écrit ensuite cattout le contenu de file_nameou STDINvers le terminal car nous n'instruisons pas le shell à manipuler STDOUT. N'oubliez pas que dans la deuxième ligne, votre shell manipule STDINde cette manière, qu'il ne pointe plus vers votre périphérique d'entrée standard mais pointe vers un fichier appelé file_namedans votre répertoire de travail actuel.

Dans l'autre cas de la ligne

man < file_name

mann'est pas censé lire quoi STDINque ce soit s'il est appelé sans argument, c'est-à-dire un tableau vide. Donc la ligne

man < file_name

équivaut à

man

Par exemple man, lira quelque chose STDIN, aussi si vous passez -l -à man. Avec cette option donnée sur la ligne de commande, vous pouvez afficher le contenu de tout ce qui se manlit STDINsur votre terminal. Donc

man -l - < file_name

fonctionnerait également (mais attention, ce mann'est pas seulement un pager, mais il analyse également l'entrée du fichier et le contenu du fichier et le contenu affiché peuvent différer).

Alors, comment STDIN, STDOUTet les arguments de ligne de commande sont interprétés dépend du développeur correspondant.

J'espère que ma réponse éclaircira les choses.

user1146332
la source
Merci pour cette explication détaillée. Pour vos derniers paragraphes, vous avez mentionné l'utilisation man -l - < file_namepour faire des maninterprètes STDINcomme arguments, mais cela échoue dans mon système avec STDERR:man -l - < tee man: invalid option -- l man, version 1.6c
steveyang
Je vous en prie. Mais je n'ai pas mentionné qu'au moins ma version de man( man-db ) lit les arguments STDINavec les arguments donnés -lsuivis de -. Il interprète simplement les données à partir STDINd'une page de manuel. Pour des explications plus détaillées des arguments valides et de la façon dont ils sont interprétés, vous devez consulter la page de manuel du programme associé. Dans votre cas, consultez man man. Il existe peut-être une option similaire pour votre man. Si vous souhaitez lire les arguments de ligne de commande pour un programme spécifique à partir de STDIN xargs(comme mentionné ci-dessus), c'est la voie à suivre.
user1146332
Je man mantrouve que celui de mon système d'exploitation ne le prend pas en charge. Quoi qu'il en soit, merci pour cette déclaration de ces deux concepts pour moi.
steveyang
J'ai modifié votre réponse pour qu'elle contienne des liens utiles au lieu de lmgtfy. La publication de liens lmgtfy est 1) grossière, 2) inutile et 3) vraiment désapprouvée sur les sites SE. Fournissez un lien ou non, mais si vous choisissez de le faire, fournissez un lien vers des informations réelles et non vers une manière sarcastique de montrer à quelqu'un comment les trouver.
terdon
12

Ils sont complètement différents. Les arguments de ligne de commande sont passés au programme dans un tableau et il peut faire ce qu'il veut avec eux; stdin est un flux d'entrée auquel le programme doit demander des données. Les programmes qui traitent les fichiers choisissent souvent de prendre en charge les deux, mais ils doivent le faire manuellement - ils vérifient si un nom de fichier a été passé comme argument de ligne de commande, et sinon ils lisent à partir de stdin à la place

Vous semblez vous attendre manà lire stdin pour trouver la page de manuel qu'il doit afficher, ce qui serait un comportement vraiment étrange; quand utiliseriez-vous cela? Le fait d' catafficher son stdin est un artefact du fait qu'il ne fait rien d'autre; Je ne pense pas qu'un autre outil fonctionne de cette façon. Par exemple, greppeut prendre un nom de fichier ou lire stdin, mais il traite les données stdin, il ne lit pas un nom de fichier stdinet l'ouvre

Si vous avez vraiment besoin de ce comportement, vous pouvez utiliser xargsce qui convertit un fichier en arguments de ligne de commande:

$ xargs man < file_name

Ou tout simplement intégrer un catappel dans l' manappel:

$ man $(cat file_name)
Michael Mrozek
la source
En bash, vous pouvez utiliser man $(<file_name).
jordanm
Re: "Je ne pense pas qu'un autre outil fonctionne de cette façon" - Perl (<>)dans une boucle fera STDINou des arguments en ligne de commande comme noms de fichiers ...
Aaron D. Marasco
@ AaronD.Marasco Je voulais dire qu'aucun outil ne prend un argument ou lit un nom de fichier depuis stdin et lit l'argument de ce fichier
Michael Mrozek
@MichaelMrozek Merci pour cette clarification. Le but que j'ai utilisé man < file_nameest de m'aider à comprendre ces deux concepts. À la lecture de votre explication, la mise en œuvre est décidée par l'auteur de la commande. Donc, si je sous droite, les findarguments prend plutôt les processus STDIN?
steveyang