为什么某些程序(如 readlink)不能从管道获取输入?

为什么某些程序(如 readlink)不能从管道获取输入?

$PATH我有一个指向我想要编辑的文件中的脚本的符号链接。我忘记了文件路径,所以我尝试执行以下操作:

$ which my_script_link | readlink

我期望输出文件路径,但它输出

> readlink: missing operand
> Try 'readlink --help' for more information

我之前在其他情况下也见过类似的行为(比如尝试将文件列表通过管道传输到 vim 中进行编辑)。我知道有解决方法,例如 subshel​​l readlink $(which my_script_link),但我想了解为什么在这种情况下,管道不能按照我想象的方式工作。

谢谢!

答案1

简单地说,因为程序不是为了这样做而编写的。由程序员决定他们的软件是否可以从 STDIN 读取或者是否需要输入文件。在 的情况下readlink,其man页面指出(强调我的):

readlink - 打印已解决符号链接或规范的文件名

概要
阅读链接[选项]...文件...

作为一般规则,从 STDIN 获取输入的程序旨在以某种方式解析该输入。当您通过管道传输数据时,readlink它会收到一个文本流,但不知道如何处理它,因为它只处理文件而不处理其内容。对于像lsorcd或等程序也是如此cp。只有处理文本/数据流的程序才能接受来自管道的输入。

答案2

程序是否从命令行参数获取输入stdin或将其作为命令行参数由设计者决定。两种方法都有其优点。然而,对于严格操作文件的程序来说,将文件名作为命令行参数传递通常比通过stdin.

最明显的原因是,在常见情况下,即仅在文件上运行程序,更容易键入:readlink file而不是echo file | readlink.

一个更微妙的问题是正确性。问题是,当文件名通过 传递时stdin,程序需要能够区分一个文件名和另一个文件名。通常,这是通过假设文件名由空格或换行符分隔来完成的,但这是不正确的,因为文件名可以包含空格。更好的方法是用空字节分隔文件名,但生成用空字节分隔的文件列表可能很不方便。

在命令行上传递文件名可以避免此问题,因为 shell 会处理程序的所有解析和引用。您可以键入touch $'foo\nbar'touch正确地将其视为包含换行符的文件名,而无需处理任何特殊的解析或引用本身。

话虽这么说,如果您想stdin为特定程序传递文件,您可以。这就是xargs目的。xargs允许您采用仅在命令行上接受参数的程序,并使其通过stdin.

换句话说,它可以让您执行以下操作:which my_script | xargs readlink

如果您想始终以readlink这种方式工作,您可以创建一个别名:alias readlink="xargs readlink"。这将允许您按照您最初想要的方式输入which my_script | readlink

答案3

对于不通过 STDIN 获取参数的命令,您可以使用以下代码杂注:

$ readlink $(which my_script_link)

例子

$ ln -s /bin/ls ~/bin/somecmd

现在检查它是否在$PATH.

$ which somecmd
~/bin/somecmd

或者首选方式,使用typeinstad of which

$ type somecmd
somecmd is /home/saml/bin/somecmd

或者只是值:

$ type -P somecmd 
/home/saml/bin/somecmd

现在我们运行readlink

$ readlink $(type -P somecmd)
/bin/ls

相关内容