Bash 为什么“>;”重定向不捕获替换的进程';史都?
在回答一个关于管道和重定向的问题时,robert提到管道还捕获了管道中替代流程的标准,而重定向则没有。为什么会这样?到底是什么导致了这种行为:Bash 为什么“>;”重定向不捕获替换的进程';史都?,bash,output-redirect,process-substitution,Bash,Output Redirect,Process Substitution,在回答一个关于管道和重定向的问题时,robert提到管道还捕获了管道中替代流程的标准,而重定向则没有。为什么会这样?到底是什么导致了这种行为: bash-4.1$ echo -e '1\n2' | tee >(head -n1) >redirect 1 bash-4.1$ cat redirect 1 2 bash-4.1$ echo -e '1\n2' | tee >(head -n1) | cat >pipe bash-4.1$ cat pipe 1 2 1 我本以
bash-4.1$ echo -e '1\n2' | tee >(head -n1) >redirect
1
bash-4.1$ cat redirect
1
2
bash-4.1$ echo -e '1\n2' | tee >(head -n1) | cat >pipe
bash-4.1$ cat pipe
1
2
1
我本以为两种形式都会产生相同的结果——后者
阅读一个不同的问题,在命令中重新排序重定向可能会产生所需的结果,这似乎是合理的,但无论顺序如何,结果总是相同的:
bash-4.1$ echo -e '1\n2' | tee >redirect >(head -n1)
1
bash-4.1$ cat redirect
1
2
bash-4.1$ echo -e '1\n2' | >redirect tee >(head -n1)
1
bash-4.1$ cat redirect
1
2
为什么stdout重定向只影响tee
,而pipe也会捕获被替换的进程head
?仅仅是“设计的”
与上述问题相关的一个想法是:我认为重定向到文件并管道化输出永远不会有意义,但在进程替换中确实有意义:
bash-4.1$ echo -e '1\n2\n3' | tee >(head -n1) >(tail -n1) >tee_out | cat >subst_out
bash-4.1$ cat tee_out
1
2
3
bash-4.1$ cat subst_out
1
3
运行
head
的shell由运行tee
的同一个shell生成,这意味着tee
和head
都继承相同的标准输出文件描述符,该文件描述符连接到管道cat
。这意味着tee
和head
都将其输出通过管道传输到cat
,从而产生您看到的行为。
echo -e '1\n2' | tee >(head -n1) > redirect
,在|
之后,只有tee
的标准输出被重定向到文件,head
仍然输出到tty。要重定向tee
和head
的标准输出,您可以编写
echo -e '1\n2' | { tee >(head -n1); } > redirect
或
为了
,
tee>(head-n1)
作为一个整体,它们的标准液通过管道输送到cat
。它在逻辑上与echo-e'1\n2'{tee>(head-n1)}>重定向TL;DR:当执行部分管道时,shell首先执行stdin/stdout的管道重定向,然后执行>/
/(echo y)>文件时,它首先分叉一次以执行复杂命令(在某些情况下可以避免,如内置),然后分叉的shell:
管道
(用于流程替换)stdin
连接到管道[1]
exec
的echo y
;exec
'edecho
继承:
- 标准DIN连接到管道[1]
- 不变标准
文件
标准输出连接到文件
exec
的echo x/proc//fd/
;exec
'edecho
继承:
- 标准数据保持不变
- 标准输出已连接到
文件
stdout
,然后分叉shell将其stdout
重定向到文件。在这种情况下,我认为这种行动顺序没有绝对必要,但我认为这样做更有意义
管道重定向
当shell遇到echo x>(echo y)| cat>文件时,它检测到一个管道并开始处理它(无分叉):
父级:创建一个管道
(对应于完整命令中唯一实际的|
)
父级:管道左侧的叉子
fork1:将其标准输出连接到管道[0]
fork1:创建一个管道子节点
(用于流程替换)
fork1:第二个echo的forks
嵌套分叉:将其stdin
连接到pipe\u subst[1]
嵌套的fork:exec
的echo y
;exec
'edecho
继承:
- 标准DIN从内叉连接到管道接头[1]
标准输出从外叉连接到管道[0]
fork1:exec
的echo x/proc//fd/
;exec
'edecho
继承:
- 标准数据保持不变
- 标准输出连接到
管道[0]
父项:管道右侧的分叉(这个分叉有时也可以避免)
fork2:将其stdin
连接到管道[1]
fork2:打开文件
fork2:将其标准输出连接到文件
fork2:exec
的cat
;exec
'edcat
继承:
- 标准DIN连接到
管道[1]
- 标准输出已连接到
文件
在这里,管道优先,即在执行管道元素的任何其他操作之前,由于管道而执行stdin/stdout的重定向。因此,这两个echo
都继承了重定向到cat
的stdout
所有这些实际上都是在进程替换之后处理文件重定向的设计结果。如果在此之前处理了>文件
重定向(就像管道重定向一样),那么>文件
也会被替换的进程继承。另一方面,echo-e
被POSIX指定为在输出时发出-e
{ echo -e '1\n2' | tee >(head -n1); } > redirect
echo -e '1\n2' | tee >(head -n1) | cat > pipe
$ echo x >(echo y) >file
y
$ cat file
x /dev/fd/63
$ echo x >(echo y) | cat >file
$ cat file
x /dev/fd/63
y