Ste*_*ett 4 shell bash command-history pipe io-redirection
将重定向与 here 文档结合起来似乎很合乎逻辑:
$ bash > foo <<EOF
echo Hello
EOF
$ less foo
Hello
Run Code Online (Sandbox Code Playgroud)
但是对于管道,它的行为有所不同:
$ bash | tee foo <<EOF
echo Hello
EOF
$ less foo
echo Hello
Run Code Online (Sandbox Code Playgroud)
同样奇怪的是,如果您立即输入“历史记录”:
$ bash | tee foo <<EOF
echo Hello
EOF
$ history
$ history
1 ...
Run Code Online (Sandbox Code Playgroud)
也就是说,第一个命令似乎仍然在新创建的 bash 中。这是怎么回事?为什么管道的行为不同?
您正在重定向tee的输入,而不是bash。用:
bash << EOF | tee foo
echo Hello
EOF
Run Code Online (Sandbox Code Playgroud)
再举几个例子来说明它是如何工作的:
bash << EO1 3<< EO\2 | tee 3<< EO3 foo 4<< EO4
fed (as a deleted temp file open in read-only mode) to bash fd 0
EO1
fed to bash fd 3 without $variable and $(cmd) expansion
EO2
fed to tee fd 3
(not that tee does anything with its fd 3)
EO3
fed to tee fd 4
(see how, like any redirection operator 3<< END can appear anywhere on
the command line (for simple commands at least))
EO4
Run Code Online (Sandbox Code Playgroud)
重定向复合命令:
{ head -n2; wc -l; } << EOF
fed as fd 0 for the whole command group
$(ps -e)
EOF
Run Code Online (Sandbox Code Playgroud)
或者:
if head -n1; then
head -n2
fi << EOF
1
2
3
EOF
Run Code Online (Sandbox Code Playgroud)
您可以重复使用相同的结束标记:
$ ls -l /proc/self/fd << E 3<< E >&2 | 3<< E 4<< E ls -l /proc/self/fd
pipe heredoc> E
pipe heredoc> E
pipe heredoc> E
pipe heredoc> E
total 0
lr-x------ 1 stephane stephane 64 Feb 24 12:50 0 -> /tmp/zshLiVzp3 (deleted)
lrwx------ 1 stephane stephane 64 Feb 24 12:50 1 -> /dev/pts/5
lrwx------ 1 stephane stephane 64 Feb 24 12:50 2 -> /dev/pts/5
lr-x------ 1 stephane stephane 64 Feb 24 12:50 3 -> /tmp/zshFLbQ7T (deleted)
lr-x------ 1 stephane stephane 64 Feb 24 12:50 4 -> /proc/25749/fd/
total 0
lr-x------ 1 stephane stephane 64 Feb 24 12:50 0 -> pipe:[70735808]
lrwx------ 1 stephane stephane 64 Feb 24 12:50 1 -> /dev/pts/5
lrwx------ 1 stephane stephane 64 Feb 24 12:50 2 -> /dev/pts/5
lr-x------ 1 stephane stephane 64 Feb 24 12:50 3 -> /tmp/zshL3KBp3 (deleted)
lr-x------ 1 stephane stephane 64 Feb 24 12:50 4 -> /tmp/zshcJjS7T (deleted)
lr-x------ 1 stephane stephane 64 Feb 24 12:50 5 -> /proc/25748/fd/
Run Code Online (Sandbox Code Playgroud)
至于为什么第一个history命令在新的bash中运行:
$ bash | tee foo <<EOF
echo Hello
EOF
$ history
$ history
1 ...
Run Code Online (Sandbox Code Playgroud)
那是因为bashstdin 仍然是终端,但它的 stdout 是一个死管(在管道的另一端,tee已从该删除临时文件重定向其 stdin,因此该管道的读取端已关闭)。
bash不会在其标准输出(死管)上写入其提示或您键入的内容的回显,而是写入终端,这样bash您就可以history在第一个提示处输入。
但是,那个history(它是一个内置函数,因此由bash进程而不是子进程执行)会将其输出写入该死管道。这样做时,bash进程将收到一个 SIGPIPE 信号(因为没有读取器)并死亡。
下一个提示将由调用 shell 发出。