[英]An issue with while read loop
關於while循環工作的一件事。
我有以下代碼:
f2(){ if [[ -t 0 ]] ; then echo "$*" ; else echo $(cat) ; fi ; }
echo -e 'a\nb\nc' | while read var ; do f2 $var ; done
對我來說有趣的是,為什么不打印'a'字母。 但是,如果我使用for循環,一切似乎都按預期工作。 像這樣:
for var in `echo -e 'a\nb\nc'`; do f2 $var ; done
希望保留這些回顯,因為它們是在stdout上提供輸出的其他腳本的替代,但它們給出的結果完全相同。 缺少一些應打印的值。
謝謝大家。
讓我們仔細看一下這一行:
echo -e 'a\nb\nc' | while read var ; do f2 $var ; done
那:
echo
命令,將其stdout重定向到管道 while
命令,將其stdin重定向到管道。 因此,使用此有用的工具,將其簡化為必要的內容:
readlink -f /dev/stdin
readlink -f /dev/stdin
(無論如何在Linux上)都會告訴我們stdin
可以解決什么。 在一個交互式外殼中,它將顯示stdin
是一個終端:
$ readlink -f /dev/stdin
/dev/pts/14
現在,讓我們回到管道:
$ echo | readlink -f /dev/stdin
/proc/28050/fd/pipe:[608866]
不出所料, stdin
是一個管道。
現在,管道的實際右側為:
| while read var ; do f2 $var ; done
其中f2
通過檢查if [[ -t 0 ]]
開始:換句話說,f2檢查stdin
是否為終端。 我們可以看到stdin
不是終端,因此f2
將繼續執行else
子句:
echo $(cat)
打印其余的stdin
,將行尾替換為空白。 stdin
重定向本來是三行, a
, b
和c
,但是read
已經讀取了第一行,所以剩下的就是b
和c
,這就是cat
將返回的內容。
不用說,邏輯是錯誤的。 為什么要讓f2
檢查其輸入是否已重定向?
更正常的做法可能是檢查是否有任何參數: if (($#)); then
if (($#)); then
。 但是由於我不知道您要做什么,所以我無法提供確定的解決方案。
盡管在這種情況下,最好修復f2
,但可以通過使用進程替換和其他文件描述符來避免在while read
循環中使用stdin
:
while read -u3 var ; do f2 $var ; done 3< <(echo $'a\nb\nc')
在這里, 3<
導致文件描述符3的重定向(未使用文件描述符)和read -u3
告訴read
從FD 3,而不是讀取stdin
。 <( command )
是進程替換 ,它創建一個名稱,該名稱可用於讀取命令的輸出。
我相信'a'進入var,其余的stdin被cat消耗/處理。
也許下面的示例可以幫助形象化這一點:
在此示例中,僅“ read”消耗標准輸入。
echo -e 'a\nb\nc' | while read var ; do echo Iterated $var ; done
Iterated a
Iterated b
Iterated c
使用cat時,read會消耗stdin的第一部分,而其余的則由cat消耗。
$ echo -e 'a\nb\nc' | while read var ; do echo $(cat); echo Iterated $var ; done
b c
Iterated a
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.