2012-08-13 54 views
2

使用bash我想讀取一行行並詢問用戶腳本是否應該在讀取每行時處理它。由於這兩行和用戶的響應來自標準輸入,如何協調文件句柄?一番搜索和審判後&錯誤,我想出了如何從標準輸入讀取數據並讀取用戶對每行數據的響應

exec 4<&0 
seq 1 10 | while read number 
do 
    read -u 4 -p "$number?" confirmation 
    echo "$number $confirmation" 
done 

這裏我們使用EXEC重開對文件句柄4標準輸入的例子,閱讀數字序列從管道標準輸入,並獲得用戶對文件的響應處理4.這似乎是太多的工作。這是解決這個問題的正確方法嗎?如果不是,那麼更好的方法是什麼?謝謝。

+0

您可能會考慮更多地解釋它是如何發生的,即「行和用戶的響應來自標準輸入」。這聽起來像是一種奇怪的做生意的方式...... – 2012-08-13 16:45:52

+0

從用戶的角度來看,命令需要像「rm -i *」那樣運行。 (有關腳本的博客文章位於[killmatching](http://calliopesounds.blogspot.com/2012/08/a-less-violent-killmatching.html)。)腳本需要在內部使用管道暴露給用戶。並且該腳本不應該由此需求給用戶帶來不便。 – 2012-08-15 17:57:56

+0

我讀過你的博客文章,你完全想要從用戶的stdin中分離出內部stdin。這意味着使用兩遍。幸運的是,您的應用程序沒有性能問題。我已經更新了我的答案。 – 2012-08-16 16:21:27

回答

0

對於您的申請,killmatching,兩個通行證完全是正確的路要走。

  • 在第一遍中,您可以將所有匹配的進程讀入數組中。這個數字很小(通常幾十個,最多幾萬個),所以沒有效率問題。該代碼將看起來像

    set -A candidates 
    ps | grep | while read thing do candidates+=("$thing"); done 
    

    (語法細節可能是錯的,我的是bash生鏽。)

  • 第二階段將通過candidates陣列環路,做互動。

另外,如果它在您的平臺上可用,您可能需要查看pgrep。這並不理想,但它可以爲您節省一些分支,比世界上所有的數組查找花費更多。

+0

如果輸入數據很大,將它全部讀入數組可能會使用大量內存和延遲處理(我認爲'seq 1 10'只是一個佔位符,或者他可以直接用'for $ seq 1 10)'。 – chepner 2012-08-13 13:22:24

+0

@chepner你好?它是一個shell腳本。如果性能是一個問題,shell可能不是這個工作的正確工具。 – 2012-08-13 16:45:20

+1

假設輸入本質上是無限的(一個日誌文件從例如,一個持續運行的進程),不要假設你可以等待輸入的結束開始處理,如果你不需要的話,用戶明確地說「腳本應該在每行被讀取時處理」。 – chepner 2012-08-13 17:06:46

3

你可以只強制read以接受來自終端的輸入,而不是更抽象的標準輸入:

while read number 
do 
    < /dev/tty read -p "$number?" confirmation 
    echo "$number $confirmation" 
done 

的缺點是你不能接受自動化(通過連接的管道閱讀例如,yes)。

+0

Is現在POSIX標準中的'/ dev/tty'? – 2012-08-13 17:11:24

+0

它在[IEEE Std 1003.1-2008] 10.1節(http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap10.html)中列出。 – chepner 2012-08-13 17:36:29

+0

在我的環境中,此用法是可以接受的。 – 2012-08-15 18:00:44

1

是的,使用額外的文件描述符是解決此問題的正確方法。管道只能將一個命令的標準輸出(文件描述符1)連接到另一個命令的標準輸入(文件描述符1)。所以當你解析一個命令的輸出時,如果你需要從其他源獲得輸入,那麼其他源必須由文件名或文件描述符給出。

我會寫不同這一點,使得重定向本地環路,但它不是一個大問題:

seq 1 10 | while read number 
do 
    read -u 4 -p "$number?" confirmation 
    echo "$number $confirmation" 
done 4<&0 

比其他的bash外殼,在沒有-u選項到read,您可以使用重定向:

printf "%s? " "$number"; read confirmation <&4 

您可能感興趣的other examples of using file descriptor reassignment

另一種方法,如pointed out by chepner,是從命名文件中讀取的,即/dev/tty,它是運行程序的終端。這使得腳本更簡單,但缺點是無法輕鬆地提供確認數據到手動腳本。