
為什麼
for i in {1..5}; do x="${i}" echo "$x"; done
不輸出
1
2
3
4
5
?
這樣做的正確方法是什麼?
(已測試for i in {1..5}; do x=$(i) echo "$x"; done
-bash: i: 未找到指令
和別的)
答案1
按要求回答您的問題
為什麼不
for i in {1..5}; do x="${i}" echo "$x"; done
輸出1
、、、、?2
3
4
5
原因與執行期間評估操作的順序有關。看看這個指令
x="${i}" echo "$x"
這是做什麼的
- 用變數的值替換變數
- 為變數分配臨時值
x
- 執行命令
所以你得到
x=1 echo ""
(或x=2 echo ""
,等等)- 在此命令的持續時間內,
x
設定為值1
- 執行命令:
echo ""
您可能認為該指令是兩個指令:為 賦值x
,輸出其值。但在 shell 語法中,您編寫的程式碼是完全合法的,因此 shell 會毫無異議地執行它。
答案2
您要求回答兩個問題:
您要求解釋為什麼當前程式碼沒有產生預期的輸出。
您詢問了編寫程式碼的正確方法,以便它確實產生預期的輸出。
查看您的程式碼,我可以看到兩種可能的解釋來解釋為什麼您以這種方式編寫程式碼:
for迴圈語法
在第一種情況下,我會說你在變數賦值後缺少一個分號。如果您想將 for 迴圈寫在一行上,那麼您需要在迴圈體中的每個指令後面放置一個分號。試試這個:
for i in {1..5}; do x="${i}"; echo "$x"; done
另一個選擇是使用多行語法編寫 for 循環,並用換行符號代替分號:
for i in {1..5}
do
x="${i}"
echo "${x}"
done
您也可以混合搭配分號和換行符,例如:
for i in {1..5}; do
x="${i}"; echo "${x}"
done
評估簡單指令
在第二種情況下,我想說您可能假設命令序言中的變數賦值(即賦值x="$i"
)發生在命令主體中的變數擴展(即${x}
in的擴展echo "${x}"
)之前。但事實並非如此。為了驗證這一點,我們可以參考頁面簡單的命令擴展在 Bash 手冊中或關於簡單指令的小節在裡面POSIX規範。這兩篇參考文獻都包含以下段落:
「簡單命令」是一系列可選的變數分配和重定向,可以任意順序,可選地後跟單字和重定向,並由控制運算子終止。
當需要執行給定的簡單命令時(即,當任何條件結構(例如 AND-OR 清單或案件語句沒有繞過簡單命令),以下擴展、賦值和重定向都應從命令文字的開頭到結尾執行:
根據以下規則被識別為變數賦值或重定向的單詞Shell 語法規則儲存以供步驟 3 和 4 的處理。
不是變數賦值或重定向的單字應該被擴展。如果擴充後仍有任何字段,則第一個字段應被視為命令名稱,其餘字段是命令的參數。
重定向應按中所述執行重定向。
每個變數賦值都應在賦值之前進行擴展,以進行波形符號擴展、參數擴展、命令替換、算術擴展和引號刪除。
請注意,步驟 2 是指令中發生變數擴充的地方,但步驟 1 告訴我們變數賦值會一直儲存到步驟 3 和echo "${x}"
4 。這解釋了為什麼您得到空輸出。echo ""
x="${i}"
有關此主題的進一步討論,請參閱以下帖子:
答案3
在 中,使用, Bourne 運算子的zsh
第三種${var::=value}
形式,其中賦值是無條件的(而不是僅當 var 未設定/為空時)。${var=value}
${var:=value}
for i in {1..5}; do echo ${x::=$i}; done
或者:
for i ({1..5}) echo ${x::=$i}
在bash
:
set -o posix # so the value of x remains after eval returns
for i in {1..5}; do x=$i eval 'echo "$x"'; done
也就是說,您需要$x
在評估包含其擴充功能的程式碼時進行設定。
對於像這裡這樣的十進制整數值,您還可以執行以下操作:
for i in {1..5}; do echo "$((x = i))"; done
或者,您始終可以${var:=value}
在設定x
為空字串後使用 Bourne 運算子。
for i in {1..5}; do x=; echo "${x:=$i}"; done