2011-10-07 71 views
0

跟進到慶典coproc - 意外的行爲

鑑於如我所料的明顯的用途coproc不起作用,如看到:

$ cat test.sh 
coproc cat auto/etc/build.cfg 
while read -u ${COPROC[0]} BRANCH TARGET SVNSRC SVNTAG BUILDTYPE DISTTYPE DISTARGS 
do 
    echo hello 
done 

$ bash -x test.sh 
+ read -u 63 BRANCH TARGET SVNSRC SVNTAG BUILDTYPE DISTTYPE DISTARGS 
+ cat auto/etc/build.cfg 
+ echo hello 
hello 
+ read -u BRANCH TARGET SVNSRC SVNTAG BUILDTYPE DISTTYPE DISTARGS 
test.sh: line 2: read: BRANCH: invalid file descriptor specification 

問題:腳本讀取一行後coproc爲什麼會消失的輸出?

+0

'$ {COPROC [0]}'仍然評估爲'echo hello'之後的空字符串以外的任何內容嗎? –

+0

@單調,沒有。它是空的。 –

+0

誰投票結束,你能解釋一下對此沒有建設性的意見嗎?如果您反對這個標題(70年代參考),改變它不那麼「幽默」。 –

回答

4

我無法重現:

bash-4.1 $ cat infile 
one 
two 
three 
four 
five 

bash-4.1 $ cat s.sh 
coproc cat infile 
while read -u ${COPROC[0]} v; do 
    echo "$v" 
done 

bash-4.1 $ bash -x s.sh 
+ read -u 63 v 
+ cat infile 
+ echo one 
one 
+ read -u 63 v 
+ echo two 
two 
+ read -u 63 v 
+ echo three 
three 
+ read -u 63 v 
+ echo four 
four 
+ read -u 63 v 
+ echo five 
five 
+ read -u 63 v 
+ echo '' 

+ read -u 63 v 

編輯:我沒有重現這樣的:

bash-4.1 $ cat s.sh 
coproc cat infile 

sleep 1 

while read -u ${COPROC[0]} v; do 
    echo "$v" 
done 

bash-4.1 $ bash -x s.sh 
+ sleep 1 
+ cat infile 
+ read -u v 
s.sh: line 5: read: v: invalid file descriptor specification 

編輯:請參閱下面的評論。


看來,合作過程超時迅速... 可能是你的系統很慢:)

號,執行的命令作爲共同加工的太快, 如果你慢它,它的工作原理:


bash-4.1 $ cat s.sh 
coproc while read -r; do 
    printf '%s\n' "$REPLY" 
    sleep 1 
done < infile 

sleep 1 

while read -u ${COPROC[0]} v; do 
    echo "$v" 
done 

bash-4.1 $ bash s.sh 
one 
two 
three 
four 
five 

無論如何,我相信這個測試案例是不恰當的。 當您需要一個雙向管道時(即您需要協同處理),您需要一個協同過程。您可以使用單個數據庫 連接(數據庫連接是資源昂貴的) 並與您的查詢和shell代碼來回。

編輯(見下面的註釋)。 (與標準輸入緩衝可以圍繞 一些非標準工具先後在這種情況下,問題stdbuf使用(最新版本的GNU的coreutils的一部分,我相信):

~/t$ cat s 
coproc stdbuf -oL -i0 mysql 

printf '%s;\n' 'show databases' >&${COPROC[1]} 

printf '\n\nshowing databases, fisrt time ...\n\n\n' 

while read -t3 -u${COPROC[0]}; do 
    printf '%s\n' "$REPLY" 
    [[ $REPLY == test ]] && { 
    printf '%s\n' 'test found, dropping it ...' 
    printf '%s;\n' 'drop database test' >&${COPROC[1]} 
    } 
done 

printf '\n\nshowing databases, second time ...\n\n\n' 


printf '%s;\n' 'show databases' >&${COPROC[1]} 

while read -t3 -u${COPROC[0]}; do 
    printf '%s\n' "$REPLY" 
done 


printf '%s\n' quit >&${COPROC[1]} 

輸出:

~/t$ bash s 


showing databases, fisrt time ... 


Database 
information_schema 
mysql 
sakila 
test 
test found, dropping it ... 
world 


showing databases, second time ... 


Database 
information_schema 
mysql 
sakila 
world 

我意識到這種方法有很多缺點......

+0

如果你在循環內部做了更復雜的事情,比如'svn status',會發生什麼?我發現上面的工作Cygwin(bash 4.1.10),但不是Fedora 14(bash 4.1.7)。然而,它在循環內部更復雜的情況下失敗了。 –

+0

「也許你的系統很慢」 - 這是一款雙核Xeon 2.6GHz四核(即8個全內核,不是HT),內存充足。 '平均負載:0.00,0.01,0。05' –

+0

「作爲協同進程執行的命令太快了」 - 這不是我期望的工作方式,基於在Java中使用協處理進程。無論協處理何時完成,其輸出都會被緩衝並且可以讀取,直到您收穫進程(waitFor)。我猜這個範式在bash中是不同的,經過一段時間我開始理解。 –