Pipe
破折號:將 STDIN 傳送到多個命令,並將它們的輸出按定義的順序輸出到 STDOUT
起初我認為這個答案是解決方案,但現在我認為我需要一個臨時文件作為緩衝區。
這不可靠:
#!/bin/sh echo 'OK' | { { tee /dev/fd/3 | head --bytes=1 >&4 } 3>&1 | tail --bytes=+2 >&4 } 4>&1
當我在終端中執行它時,有時我會得到:
好的
有時我會得到:
柯
_
似乎完全隨機。因此,作為一種解決方法,我將輸出寫入文件並在管道完成後將其
tail
讀回。stdout
#!/bin/sh echo 'OK' | { { tee /dev/fd/3 | head --bytes=1 >&4 } 3>&1 | tail --bytes=+2 >file } 4>&1 cat file
這可以在
dash
沒有臨時文件的情況下完成嗎?Shell 變數作為緩衝區也不是一個選項,因為輸出可能包含 NUL 字節。
如果您想並行執行消費者和生產者,但序列化消費者的輸出,則需要延遲第二個消費者的輸出。為此,您需要以某種方式儲存其輸出,最好的方法是使用臨時文件。
與
zsh
:{cat =(producer > >(consumer1 >&3) | consumer2)} 3>&1
bash
有一個問題是它不等待程序替換命令,所以你必須在那裡使用討厭的工作。在這裡,我們使用
=(...)
程序替換的形式將輸出儲存comsumer2
在一個臨時文件中,cat
然後再儲存。我們不能為超過 2 個消費者這樣做。為此,我們需要手動創建臨時文件。不使用
=(...)
時,我們必須手動清理臨時文件。我們可以通過預先創建和刪除它們來處理它,這樣就不必擔心腳本被殺死的情況。仍然zsh
:tmp1=$(mktemp) && tmp2=$(mktemp) || exit { rm -f -- $tmp1 $tmp2 producer > >(consumer1) > >(consumer2 >&3) > >(consumer3 >&5) cat <&4 <&6 } 3> $tmp1 4< $tmp1 5> $tmp2 6< $tmp2
編輯(我最初錯過了需要解決方案的事實
dash
)對於
dash
(或任何沒有在 fds 上設置 close-on-exec 標誌並使用管道而不是套接字對的 POSIX shell|
),以及/dev/fd/x
支持的系統:tmp1=$(mktemp) && tmp2=$(mktemp) || exit { rm -f -- "$tmp1" "$tmp2" { { { producer | tee /dev/fd/4 /dev/fd/6 | consumer1 >&7 } 4>&1 | consumer2 >&3 } 6>&1 | consumer3 >&5 } 7>&1 cat - /dev/fd/6 <&4 } 3> "$tmp1" 4< "$tmp1" 5> "$tmp2" 6< "$tmp2"
這將適用於 Linux 上的
dash
,bash
,zsh
,mksh
,busybox sh
,但不適用於. 這種方法不能超過 4 個消費者,因為我們僅限於 fds 0 到 9。posh``ksh93