2021-05-12 14:32:11
shell中while迴圈的陷阱
在寫while迴圈的時候,發現了一個問題,在while迴圈內部對變數賦值、定義變數、陣列定義等等環境,在迴圈外面失效。
一個簡單的測試指令碼如下:
#!/bin/bash
echo "abc xyz" | while read line
do
new_var=$line
done
echo new_var is null: $new_var?
執行結果證明,$new_var的結果是空值。在google上查了查,才發現問題出在管道上。
先看看下面的內容。
while迴圈的寫法有好幾種,它的語法結構為:
while test_cmd_list; do cmd_list; done
但更經常地,while迴圈更多地用於讀取標准輸入的內容來實現迴圈。有以下幾種寫法:
寫法一:使用管道傳遞內容,這是用的最多、但卻最爛的寫法
echo "abc xyz" | while read line
do
...
done
寫法二:
while read line
do
...
done <<< "abc xyz"
寫法三:從檔案中讀取內容
while read line
do
...
done </path/filename
方法四:採用進程替換
while read var
do
...
done < <(cmd_list)
方法五:改變標準輸入
exec <filename
while read var
do
...
done
儘管寫法有多種,但它們並不等價。方法一中使用的是管道符號,這使得while語句在子shell中執行,這意味著while語句內部設定的變數、陣列、函數等在迴圈外部都不再生效。這正是文章開頭所說的陷阱。更簡單的:echo haha | a=5,在命令執行結束後,變數a的值也不再是5。其餘4種寫法,while語句都不在子shell中執行,因此都不會出現文章開頭所說的問題。
例如,使用寫法二的here string代替寫法一:
#!/bin/bash
while read line
do
new_var=$line
done <<< "abc xyz"
echo new_var is null: $new_var?
或者使用寫法四的進程替換:
#!/bin/bash
while read line
do
new_var=$line
done < <(echo "abc xyz")
echo new_var is null: $new_var?
由此可以說,在上面的5種寫法中,使用的最廣泛的寫法一雖然最簡單、方便,但其實是最爛的一種。
本文永久更新連結地址:http://www.linuxidc.com/Linux/2017-08/146534.htm
相關文章