Shell-Script

當兩個子外殼寫入標準輸出時排序輸出

  • October 21, 2020

我有以下形式的命令

input | tee >(subshell) | mainshell

subshel​​l 和 mainshell 都寫入標準輸出。所以他們的輸出是不同步的。例如

echo "Hello\nWorld" | tee >(grep -o ell | tr 'a-z' 'A-Z') | grep orld | sed 's/orl/ORL/g'

上面的命令列印

ELL
WORLd

有時和

WORLd
ELL

其他時間。

有沒有一種簡單的方法來確保它們符合預期的順序,而不必使用臨時文件/命名的 fifos?可能打開一些文件描述符重定向會有所幫助嗎?

更新:

按順序,我的意思是輸出主外殼,然後是子外殼(反之亦然)。如果它以一種或另一種方式是確定性的,我可以根據我的需要交換它們。

同樣可以通過命名 fifo 來實現,如下所示

mkfifo f1 f2
echo "Hello\nWorld" | tee >(grep -o ell | tr 'a-z' 'A-Z' > f1) | grep orld | sed 's/orl/ORL/g' > f2 &
cat f1 f2
rm f1 f2

我想知道是否可以避免臨時 fifo 或文件。

GNU Parallel 擁有--tee並且--keep-order您可以強制訂單保持不變:

ell() {
 grep -o ell | tr 'a-z' 'A-Z'
}
orld() {
 grep orld | sed 's/orl/ORL/g'
}
export -f ell
export -f orld

echo "Hello\nWorld" | parallel -k --tee --pipe ::: ell orld

但是,它確實在幕後使用了 fifos 和 tempfiles。但是,如果您的目標只是不必自己處理,那麼它可能是一個解決方案。

此解決方案使用 tmpfiles,但它們幾乎立即取消連結:

myfunc1() { grep -o ell | tr 'a-z' 'A-Z'; }
myfunc2() { grep orld | sed 's/orl/ORL/g'; }

touch tmp1 tmp2
(
   echo "Hello\nWorld" |
       tee >( (rm tmp1; myfunc1) > tmp1 ) |
       (rm tmp2; myfunc2) > tmp2
   cat <&3
   cat <&4
) 3< tmp1 4< tmp2

或更短:

(
   rm tmp1 tmp2
   echo "Hello\nWorld" |
       tee >( grep -o ell | tr 'a-z' 'A-Z' >&5 ) |
       grep orld | sed 's/orl/ORL/g' >&6
   cat <&3
   cat <&4
) 5> tmp1 6> tmp2 3< tmp1 4< tmp2

有沒有一種簡單的方法來確保它們符合預期的順序,而不必使用臨時文件/命名的 fifos?可能打開一些文件描述符重定向會有所幫助嗎?

並不真地。和>(...)...|...shell 並行執行。此外,unix 管道/終端/流套接字/等不是保留邊界的——不能保證單次寫入不會在另一端變成多次讀取(反之亦然)。

為了強制執行某些命令,您可以使用諮詢鎖定——查看flock(1)flock(2)聯機幫助頁。subshell如何使這項工作在很大程度上取決於mainshell程序的工作方式。盲目地鎖定非協作程序很容易導致死鎖(如果它確實有效)。

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