2017-03-15 70 views
0

我終於遇到了令人驚訝的標準輸入法行爲,當管道進入一段時間閱讀循環。bash while read loop和stdin - 強制嵌套命令的stdin to tty?

考慮以下幾點:

find . | while read file; 
do 
    echo "==[$file]=="; 
    cat; 
done 

在這種情況下,cat只是一個替身,從標準輸入接收輸入的任何命令。令人驚訝的是(至少對我來說)cat的STDIN實際上是來自find,所以它吞噬了其餘的find輸出。

假設你想直接從tty與cat的地方進行交互。例如。假設您想運行一個腳本,而不是cat,該腳本可能會提出您想要以交互方式回覆的問題("<file> exists: Overwrite? [y/n]")。

有沒有辦法強制內部命令的STDIN是tty?

我發現了很多類似的問題,這包括:Why redirect stdin inside a while read loop in bash?

但我不明白的回答不夠好​​,得到它的工作。

(編輯:在澄清對其他問題的光,我現在正在考慮這個這個問題的一個副本。)

+0

哪一部分,特別是* *,是很難理解嗎? (我實際上只是修改了代碼,以便在不到一小時前添加一些評論;希望自己能夠滿足)。 –

+0

......雖然 - 後續描述如何確切的其他答案沒有解決您的問題將不勝感激。 (一種可能性是我們會在這裏創建一個明顯不同的新問題 - 但另一個可能是提高原有的足以使其更有用的另一個問題也增加了網站的價值)。 –

+1

這簡直就是你的bash比我的強得多。 我看了你的答案你添加的代碼註釋之前。這讓我明白了'cat'的stdin從'find'中吞噬了一切,我沒有理解。我投了票,這可能會引發你添加評論。 我做'2>&1'之前大致瞭解,但這個東西是所有外國對我說:'EXEC 3 <的/ dev/tty的|| exec 3 <&0; exec 3 <& - '。我嘗試添加這些東西給我,但它不適用於我(因爲我遺漏了「&」)。 評論幫助我更好地理解它。 – adfaklsdjf

回答

2

我下面的東西少一些問題的例子替換cat

read_a_line() { local line; read -r line; echo "Read line: $line"; } 

這樣,它只能讀取一個線每個循環調用輸入的,而不是讀一路EOF。否則,儘管如此,我正在努力將變化保持在最小範圍內,以專注於眼前的問題。

請參閱BashFAQ #24討論爲什麼最好將流程替換重定向到您的循環而不是管道到循環。


首先,你可以簡單地從/dev/tty

find . | while read file; 
do 
    echo "==[$file]==" 
    read_a_line </dev/tty 
done 

第二個重定向頁面,則可以標準輸入複製到不同的文件描述符,以後重新使用它:

exec 3<&0 # make FD 3 a copy of FD 0 
find . | while read file; do 
    echo "==[$file]==" 
    read_a_line <&3 
done 
exec 3<&- # close FD 3 now that we're done with it 

三,您可以嘗試做都是 - 試圖讓FD 3(或者你選擇的任何其他的FD大於2)開放給/ dev/tty,但是如果失敗的話,將它作爲原始stdin的備份。

exec 3</dev/tty || exec 3<&0 
find . | while read file; do 
    echo "==[$file]==" 
    read_a_line <&3 
done 
exec 3<&- 
+0

感謝您的非常徹底的答案。現在我已經得到了解決方案#1和#2在我的情況下工作。正如我對原始問題所評論的那樣,直到您添加代碼註釋之前,我纔在其他線程的解決方案中理解;現在更清楚了。再次感謝。 – adfaklsdjf

1

這個例子可以幫助:

{ 
while IFS= read -r -d '' file 
do 
    read -u3 -p "what to do with: [$file]?> " action 
    printf "got [$action] for the [$file]\n\n" 
done < <(find . -print0) 
} 3<&0 
  • 整個腳本的標準輸入reditected到FD3
  • 和內部whilefind
  • read讀取重定向從fd3 - 例如從對方的回答的終端
+0

是否有一個原因,它的'()單曲在外面,而不是'{}'S(避免子shell的性能開銷,同時仍然允許範圍的重定向?) –

+0

...其實,什麼正在通過添加額外的語法,只是'3 <&0'完成'完成'後不能完成? –

+0

@CharlesDuffy的'{}'是更好:)但是,像2ms的開銷.... – jm666