$PATH
我有一个指向我想要编辑的文件中的脚本的符号链接。我忘记了文件路径,所以我尝试执行以下操作:
$ which my_script_link | readlink
我期望输出文件路径,但它输出
> readlink: missing operand
> Try 'readlink --help' for more information
我之前在其他情况下也见过类似的行为(比如尝试将文件列表通过管道传输到 vim 中进行编辑)。我知道有解决方法,例如 subshell readlink $(which my_script_link)
,但我想了解为什么在这种情况下,管道不能按照我想象的方式工作。
谢谢!
答案1
简单地说,因为程序不是为了这样做而编写的。由程序员决定他们的软件是否可以从 STDIN 读取或者是否需要输入文件。在 的情况下readlink
,其man
页面指出(强调我的):
readlink - 打印已解决符号链接或规范的文件名
概要
阅读链接[选项]...文件...
作为一般规则,从 STDIN 获取输入的程序旨在以某种方式解析该输入。当您通过管道传输数据时,readlink
它会收到一个文本流,但不知道如何处理它,因为它只处理文件而不处理其内容。对于像ls
orcd
或等程序也是如此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
或者首选方式,使用type
instad of which
:
$ type somecmd
somecmd is /home/saml/bin/somecmd
或者只是值:
$ type -P somecmd
/home/saml/bin/somecmd
现在我们运行readlink
:
$ readlink $(type -P somecmd)
/bin/ls