下面这行是显而易见的:
echo "bla" | foo | bar
但下面的人也这样做吗?
echo "bla" | bar <(foo)
echo "bla" | bar < <(foo)
哪个和从标准输入读取“bla”,为什么foo
?bar
我的意思是,当然,我可以对其进行编码并检查它,但我不确定它是否是定义的行为,或者我正在利用我不应该依赖的功能。
答案1
这是依赖于 shell 的,并且没有记录在案的 AFAICS。在ksh
和 中bash
,在第一种情况下,foo
将与 共享相同的标准输入bar
。他们将为输出而战echo
。
例如,
$ seq 10000 | paste - <(tr 1 X)'
1 X
2 X042
3 X043
4 X044
5 X045
[...]
您会看到从的输出paste
中读取每隔一个文本块的证据,同时读取其他文本块。seq
tr
使用zsh
,它获取外部标准输入(除非它是终端并且 shell 不是交互式的,在这种情况下它会从/dev/null
中重定向cmd &
)。ksh
(它的起源),zsh
并且bash
是唯一支持进程替换的类 Bourne shell。
在 中echo "bla" | bar < <(foo)
,请注意,bar
的 stdin 将是由 的输出提供的管道foo
。这是明确定义的行为。在这种情况下,看起来的 stdin 是所有,和中foo
提供的管道。echo
ksh
zsh
bash
如果您希望在所有三个 shell 中具有一致的行为,并且能够面向未来,因为行为可能会因未记录而发生变化,我会这样写:
echo bla | { bar <(foo); }
可以肯定的是foo
, 的 stdin 也是来自的管道echo
(但我不明白你为什么要这样做)。或者:
echo bla | bar <(foo < /dev/null)
foo
为了确保不是从管道中读取echo
。或者:
{ echo bla | bar 3<&- <(foo <&3); } 3<&0
让foo
's stdin 成为外部标准输入,就像当前版本的zsh
.
答案2
echo "bla" | foo | bar
: 的输出echo "bla"
被重定向到foo
,其输出被重定向到bar
。
echo "bla" | bar <(foo)
:那个通过管道将输出传递echo "bla"
给bar
。但bar
执行时带有参数。参数是文件描述符的路径, 的输出foo
将发送到该文件描述符。此参数的行为类似于包含foo
.所以,那不一样。
echo "bla" | bar < <(foo)
:人们可能会假设 的输出echo "bla"
应该发送到bar
并且整个语句等同于第一个语句。但是,这是不正确的。发生以下情况:因为输入重定向<
是在管道 ( |
) 之后执行的,所以会覆盖它。所以echo "bla"
没有通过管道传输到酒吧。相反, 的输出foo
被重定向为标准输入到bar
。要清除此问题,请参阅以下命令和输出:
$ echo "bla" | cat < <(echo "foo")
foo
如您所见,echo "bla"
已被 取代echo "foo"
。
现在看这个命令:
$ echo "bar" | cat < <(awk '{printf "%s and foo", $0}')
bar and foo
Soecho "bar"
通过管道传输到awk
,它读取 stdin 并将字符串添加and foo
到输出中。该输出通过管道传输到cat
.