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

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

我可以使用任一形式来执行该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

答案1

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

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

您要调用的程序如何解释参数(位于数组中)取决于它的编程方式。对于参数的语法应该是什么样子有一些准标准,但一般来说程序员是完全自由的。因此,第一个参数可以解释为文件名或程序员在编写程序时想到的任何名称。

如果您将特殊字符<或添加>到命令行,shell 不会将后续单词附加<>将传递给程序的数组中。在有了<>给定的情况下,shell 开始制作一些奇特的东西,并受到底层内核的支持(关键字管道)。要掌握正在发生的事情,您必须了解STDINSTDOUT(因为它没有立即相关,我省略STDERR)是什么。

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

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

在两条线的情况下

cat file_name
cat < file_name

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

在该行的另一种情况下

man < file_name

manSTDIN如果不带参数(即空数组)调用它,则不会从中读取任何内容。所以这条线

man < file_name

等于

man

例如,如果您传递到,man也会从 读取一些内容。通过在命令行上给出此选项,您可以显示从终端上读取的任何内容的内容。所以STDIN-l -manmanSTDIN

man -l - < file_name

也可以工作(但要小心,man它不仅仅是一个寻呼机,而且还解析文件的输入,因此文件内容和显示的内容可能不同)。

因此,如何解释STDINSTDOUT和命令行参数完全取决于相应的开发人员。

我希望我的回答可以澄清事情。

答案2

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

您似乎期望man阅读 stdin 来查找它应该显示的手册页,这将是一个非常奇怪的行为;你什么时候会用它?显示其 stdin 的事实cat是它不执行任何其他操作这一事实的产物;我认为没有任何其他工具可以这样工作。例如,grep可以获取文件名或从中读取stdin,但它处理 上的数据stdin,它不会从中读取文件名stdin然后打开它

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

$ xargs man < file_name

或者只是在调用cat中嵌入一个调用man

$ man $(cat file_name)

相关内容