STDIN和传递给命令的参数之间有什么区别?


16

我可以使用任一种形式执行该cat方法:

cat file_name
cat < file_name

结果是一样的

然后我想以man以下格式执行stdin

man < file_name

虽然file_name包含:

# file_name
cat

但是它弹出 What manual page do you want?而不是执行man cat

我想知道为什么cat可以接受stdin但不能接受man。命令行参数和之间有什么区别stdin

Answers:


21

您的问题与您使用的Shell如何解析命令行上的用户输入密切相关。

如果命令行上的第一个单词是位于特殊文件夹中的程序(主要由定义PATH),并且不再提供任何特殊字符(取决于您使用的shell),则所有由空格或制表符分隔的后续单词都将传递到程序采用特殊形式,即数组。每个单词作为数组中的一个元素。

您要调用的程序如何解释参数(位于数组中)取决于程序的编程方式。关于参数语法的外观,存在一些准标准,但总的来说,程序员是完全免费的。因此,第一个参数可以解释为文件名,也可以解释为程序员在编写程序时所想到的任何内容。

如果您在命令行中添加了特殊字符<>命令行,则外壳程序将不追加<>也不会在将要传递给程序的数组中添加后续单词。有了<或有了>外壳程序,外壳底层的内核(关键字管道)就开始制作精美的东西。为了掌握发生了什么事情,你必须了解STDINSTDOUT(因为它不是立即与我省略STDERR)是。

您在终端上看到的所有可见内容(大多数情况下是显示器的一部分)都是由Shell或您先前调用的任何其他程序编写的,都写入了一个特殊文件(在Unix中,一切都是一个文件)。此文件具有特殊ID,称为STDOUT。如果程序要从键盘读取数据,则它不会直接轮询键盘(至少在大多数情况下),而是从名为的特殊文件中读取数据STDIN。在内部,此文件连接到您的标准输入设备,大多数情况下是键盘。

如果外壳读取<>在解析的命令行中,它会在相应程序运行时对其进行操作STDINSTDOUT以特定种类进行操作。STDIN并且STDOUT不再指向终端或标准输入设备,而是指向命令行中的后续文件名。

在两行的情况下

cat file_name
cat < file_name

观察到的行为是相同的,因为相应的开发人员从文件cat读取数据STDIN或从文件读取数据,文件的名称作为第一个命令行参数给出(这是外壳传递给数组的第一个元素cat)。由于我们不指示shell进行操作,因此随后cat将整个内容写入file_name或写入STDIN终端STDOUT。请记住,在第二行中,您的外壳STDIN以这种方式进行操作,它不再指向标准输入设备,而是指向file_name当前工作目录中的一个文件。

在其他情况下

man < file_name

manSTDIN如果不带任何参数(即空数组)进行调用,则并不意味着要读取任何内容。所以这条线

man < file_name

等于

man

例如man将读取的东西STDIN,太多,如果你传递-l -man。使用命令行上给出的此选项,您可以显示manSTDIN终端读取的任何内容。所以

man -l - < file_name

也将起作用(但要注意man,不仅是寻呼机,而且还会解析文件的输入,因此文件内容和显示的内容可能会有所不同)。

因此,如何STDINSTDOUT以及命令行参数被解释为全部达到相应的开发者。

我希望我的回答可以解决问题。


感谢您的详细说明。在您的最后几段中,您提到了使用man -l - < file_namemake 作为参数进行man解释STDIN,但是在我的系统中它失败了STDERRman -l - < tee man: invalid option -- l man, version 1.6c
steveyang 2012年

别客气。但我并没有提到,至少我的版本man人-DB)从参数读取STDIN与给定参数-l之后-。它只是将数据解释STDIN为手册页。有关有效参数及其解释的详细说明,您必须查阅相关程序的手册页。您的情况请咨询man man。也许您有一个类似的选择man。如果您想从中读取特定程序的命令行参数STDIN xargs(如上文所述),则应该这样做。
user1146332 2012年

man man发现我的操作系统中的一个不支持它。无论如何,感谢我对这两个概念的声明。
steveyang 2012年

我编辑了您的答案,因此它包含实际上有用的链接,而不是lmgtfy。张贴lmgtfy链接是:1)粗鲁,2)毫无帮助和3)在SE网站上真的皱了皱眉。提供链接或不提供链接,但如果您选择这样做,则提供指向实际信息的链接,而不是提供向别人展示如何找到它的讽刺方式。
terdon

12

他们是完全不同的。命令行参数以数组的形式传递给程序,它可以使用它们执行所需的操作。stdin是程序必须从中请求数据的输入流。处理文件的程序通常选择同时支持这两种程序,但它们必须手动进行支持-它们检查文件名是否作为命令行参数传递,如果不是,则从stdin读取

您似乎希望man阅读stdin来找到应该显示的手册页,这确实是一种奇怪的行为。您何时会使用它?这一事实cat显示其标准输入是,它并没有别的事实的假象; 我认为没有其他工具可以那样工作。例如,grep可以使用文件名或从中读取文件stdin,但它处理上的数据stdin,但不从文件中读取文件名stdin,然后将其打开

如果确实需要此行为,则可以使用xargs,它将文件转换为命令行参数:

$ xargs man < file_name

或者只是将cat呼叫嵌入到man呼叫中:

$ man $(cat file_name)

在bash中,您可以使用man $(<file_name)
jordanm 2012年

回复:“我认为没有其他工具可以这样工作”-Perl可以(<>)在循环中使用STDIN命令行参数或将命令行参数作为文件名...
Aaron D. Marasco 2012年

@ AaronD.Marasco我的意思是,没有工具会接受参数或从stdin读取文件名并从该文件读取参数
Michael Mrozek

@MichaelMrozek感谢您的澄清。我使用的目的man < file_name是帮助自己理解这两个概念。阅读您的解释,实现由命令作者决定。因此,如果我说得对,则find接受参数而不是处理STDIN?
steveyang
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.