Bash

Bash:使用 tee 的 for 循環中的變數範圍

  • March 8, 2017

考慮:

numbers="1 111 5 23 56 211 63"
max=0

for num in ${numbers[@]}; do

     [ $num -gt $max ]\
          && echo "old -> new max = $max -> $num"\
          && max=$num

done | tee logfile

echo "Max= $max"

如果我刪除| tee logfilemax 變數正確列印為 211,但如果我把它留在我得到Max= 0.

到底是怎麼回事?

管道的每一側都在一個子shell 中執行。子shell 是原始shell 程序的副本,它以相同的狀態開始,然後獨立進化¹。在子 shell 中設置的變數不能轉義回父 shell。

在 bash 中,您可以使用程序替換,而不是使用管道。這與管道的行為幾乎相同,除了循環在原始 shell 中tee執行並且只在子 shell 中執行。

for num in "${numbers[@]}"; do
 if ((num > max)); then
   echo "old -> new max = $max -> $num"
   max=$num
 fi
done > >(tee logfile)
echo "Max= $max"

當我這樣做時,我在您的腳本中更改了一些內容:

請注意,管道解決方案和 subshel​​l 解決方案之間存在細微差別:管道命令在兩個命令都退出時完成,而具有程序替換的命令在主命令退出時完成,而無需等待程序替換中的程序。這意味著當您的腳本完成時,日誌文件可能沒有完全寫入。

另一種方法是使用其他通道從子shell 到原始shell 程序進行通信。您可以使用臨時文件(靈活,但更難做正確 - 將臨時文件寫入適當的目錄,避免名稱衝突(使用mktemp),即使出現錯誤也將其刪除)。或者您可以使用另一個管道來傳達結果並在命令替換中獲取結果。

max=$({ { for … done;
         echo "$max" >&4
       } | tee logfile >&3; } 4>&1) 3&>1

的輸出tee轉到文件描述符 3,該文件描述符被重定向到腳本的標準輸出。的輸出echo "$max"轉到文件描述符 4,該文件描述符被重定向到命令替換。

引用自:https://unix.stackexchange.com/questions/348175