簡體   English   中英

While讀取循環問題

[英]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重定向本來是三行, abc ,但是read已經讀取了第一行,所以剩下的就是bc ,這就是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM