Shell指令碼中使用變數作為for迴圈範圍
我們知道在shell指令碼中,可以通過{x..y}
這樣的表示式來表示一個從x到y的數列
echo {1..10} 1 2 3 4 5 6 7 8 9 10
這個用法在shell腳本里叫做Brace Expansion
。
因此我們常利用這個表示式來作為迴圈的次數,如:
for i in {1..10} do echo "$i" done
可以得到從1到10的輸出結果。
但是如果我們想輸出從1到一個變數的結果,這個變數從其他地方獲取:
NUM=10 for i in {1..$NUM} do echo "$i" done
得到的結果卻是
{1..10}
先說解決方案
放棄使用{x..y}
這樣的表示式:
NUM=10 for i in $(seq 1 $NUM) do echo "$i" done
原理
seq
命令的原理就不說了,這裡說說為什麼不能在{ }
中使用變數。其實原因寫在bash的man手冊中:
Brace expansion is performed before any other expansions, and any characters special to other expansionsarepreservedin the result.It is strictly textual.Bash does not apply any syntactic interpretation to the context of the expansion or the text between the braces.
大意是說,Bash中會最先展開{ }
中的內容,這個時候$NUM
還不會被具體的值替代,所以是i
在迴圈中讀取的是‘{1..$NUM}’
的一個完整的字串,輸出時$NUM
會被10替代,就有了'{1..10}'
這樣的結果。
關於Bash中的展開 (expansion) 順序,其實有不少值得注意的地方,一不留神可能就會踩坑,還是老前輩那句:指令碼猛於虎。