Bash

為什麼管道和重定向與這裡的文件不同?

  • February 25, 2014

將重定向與此處文件相結合似乎很合乎邏輯:

$ bash > foo <<EOF
echo Hello
EOF

$ less foo
Hello

但是對於管道,它的行為會有所不同:

$ bash | tee foo <<EOF
echo Hello
EOF

$ less foo
echo Hello

同樣奇怪的是,如果您立即輸入“歷史”:

$ bash | tee foo <<EOF
echo Hello
EOF
$ history
$ history
1 ...

也就是說,第一個命令似乎仍然在新創建的 bash 中。這是怎麼回事?為什麼管道的行為不同?

您正在重定向tee’s 的輸入,而不是bash’s. 採用:

bash << EOF | tee foo
echo Hello
EOF

再舉幾個例子來說明它是如何工作的:

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

重定向複合命令:

{ head -n2; wc -l; } << EOF
fed as fd 0 for the whole command group
$(ps -e)
EOF

或者:

if head -n1; then
 head -n2
fi << EOF
1
2
3
EOF

您可以重複使用相同的結束標記:

$ 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/

至於為什麼第一個history命令在那個新bash的 in 中執行:

$ bash | tee foo <<EOF
echo Hello
EOF
$ history
$ history
1 ...

那是因為bashstdin 仍然是終端,但它的 stdout 是一個死管道(在管道的另一端,tee已從該刪除臨時文件重定向其 stdin,因此該管道的讀取端已關閉)。

bash不會寫它的提示或您在其標準輸出(死管道)上鍵入的內容的迴聲,而是寫到終端,這樣bash您就可以history在第一個提示下輸入。

但是,那個history(這是一個內置的,由bash程序執行,而不是子程序)會將其輸出寫入該死管道。這樣做時,該bash程序將收到一個 SIGPIPE 信號(因為沒有閱讀器)並死亡。

下一個提示將由呼叫 shell 發出。

引用自:https://unix.stackexchange.com/questions/116681