我已经看到了这两种方法<<<'foo'
,并<(echo 'foo')
建议将其作为回显管道的替代方案(echo foo | cat
)。
当我将这两个结构与 cat 一起使用时,我得到:
$ cat <<<'foo'
foo
$ cat <(echo 'foo')
foo
到目前为止,也是如此。
然而,当您直接在 shell 上使用它们时,差异就会变得明显:
$ <<<'foo'
foo
$ <(echo 'foo')
zsh: permission denied: /dev/fd/12
我正在使用 zsh,而 bash 似乎以<<<
不同的方式处理这种情况,根本不打印任何内容,但与这种情况下的 zsh 相同<()
。
但真正引发我问题的是一个差异:
$ diff <<<"/mypath" <(pwd)
diff: missing operand after `/dev/fd/63'
diff: Try `diff --help' for more information.
很明显,这两种类型的 shell 重定向之间存在根本区别。谁能解释其中的区别吗?
答案1
<<< text
是一个重定向,如果影响命令的文件描述符(这里是 0,但4<<< text
会影响 fd 4)。
while<(...)
是扩展/替换,而不是重定向。它扩展为文件名。如果插入到命令中,这会影响传递给命令的参数。
cat <(echo test)
cat
使用类似文件作为参数运行/dev/fd/12
。而且它的 fd 12 在管道的读取端也是打开的。cat
不会从它的 fd 12 中读取,但是当它打开文件时/dev/fd/12
,它将获得一个新的 fd(可能是 3),它指向与 fd 12 相同的管道。
同时echo test
在后台运行,其 fd 1 连接到同一管道的写入端,因此echo
和cat
最终将通过该管道进行连接(尽管该通信通道的建立比 更复杂echo text | cat
)。
cat <<< text
运行不带参数的 cat 并打开其 fd 0 以读取包含test\n
.
zsh 解释
<<< test
作为
$NULLCMD <<< test
($NULLCMD
通常是cat
)每当您运行仅包含重定向的内容时都会发生这种情况(除非只有一个<
重定向,在这种情况下$READNULLCMD
(通常是寻呼机)会被使用))。
在:
<(echo text)
没有重定向,只有一个进程替换,扩展为一个 /dev/fd/12 参数。这就是要求 shell 执行该文件。
在 zsh 中,使用以下命令并没有真正的好处:
cat <(echo test)
cat < <(echo test)
超过
echo test | cat
您可以在其他 shell(例如 bash)中看到此构造,例如:
IFS= read -r var < <(echo text)
但那是因为在这些 shell 中,echo text | IFS= read -r var
它不起作用,因为read
它是在子进程中运行的。情况并非如此zsh
。
进程替换对于仅接受通过文件名作为参数(而不是通过标准输入)输入的命令非常有用,当您需要将多个输入传递给命令(只有一个标准输入)时,就像diff <(cmd1) <(cmd2)
.
和zsh
之间的一个区别是,后者不等待。虽然它确实等待和in (如果只是为了使两个退出状态都可用)。与相比。cmd1 | cmd2
cmd2 < <(cmd1)
zsh
cmd1
cmd1
cmd2
cmd1 | cmd2
$pipestatus
sleep 1 | uname
uname < <(sleep 1)
cmd <<< foo
cmd
当需要能够查找其输入时会很有用(因为在 中zsh
,像此处文档这样的此处字符串是使用临时文件而不是管道实现的)。