
建議使用 IFS 循環逗號分隔的列表,例如這裡。但是,我看到了
sentences="Hello World,Questions"
IFS=, sentences1=($sentences) # if we comment this line then loop is fixed
sentences2=$sentences
for sentence in ${sentences2[@]};
do
for i in $(seq 1 2);
do
#This is fine - prints a new word every line
#echo $sentence
#This is fine - prints new number every line
#echo $i
echo $i $sentence
done
done
產生
1
2 Hello World
1
2 Question
代替
1 Hello World
2 Hello World
1 Question
2 Question
想要的。曾經是一個?
答案1
這裡的主要問題是第二行將IFS=, sentences1=($sentences)
IFS 永久設定為“,”;這意味著您在腳本的其餘部分中會遇到奇怪且意外的解析行為。請注意,對於類似 的情況IFS=, read ...
,不會發生這種情況,因為 IFS 分配被視為僅適用於命令read
;但在 中IFS=, sentences1=($sentences)
,沒有真正的指令,只有賦值,因此賦值被視為應用於整個 shell。
那麼,讓我們看看腳本的其餘部分發生了什麼。sentences2=$sentences
只是複製sentences
到sentences2
,所以for sentence in ${sentences2[@]}
有點奇怪。sentences2
不是一個數組(只是一個普通的字串),所以該[@]
位不執行任何操作,但由於 IFS 仍然是“,”,它會“分詞”成“Hello World”和“Questions”——即你得到正確的結果,但出於錯誤的原因。
(注意:如果它是一個實際的數組,您需要在它周圍加上雙引號,以for sentence in "${sentences2[@]}"
防止元素被分詞。)
下一個命令for i in $(seq 1 2)
是真正的麻煩開始的地方。seq 1 2
列印“1[newline]2[newline]”,該$( )
構造會修剪尾隨的換行符,然後“1[newline]2”進行分詞 - 但由於那裡沒有逗號,因此它被視為一個單字(這恰好發生在包含換行符)。因此,內部循環僅運行一次,i
設定為“1[newline]2”。
下一行echo $i $sentence
列印“1[newline]2”,後面跟著一個空格,然後是 的內容sentence
。在第一次迭代中,sentence
設定為“Hello World”,列印:
1
2 Hello World
……中間的換行符使得這看起來像是正在列印的兩件事,但它實際上只是echo
碰巧包含換行符的一個。
因此,有兩個重要建議:首先,當您變更 IFS 時,請稍後再將其變更回來。其次,始終使用雙引號變數引用以避免意外的分詞(和通配符擴展)。這是我從腳本中得到的內容:
#!/bin/bash
sentences="Hello World,Questions"
saveIFS="$IFS"
IFS=, sentences1=($sentences)
IFS="$saveIFS" # Set IFS back to normal!
for sentence in "${sentences1[@]}"; do # Note double-quotes, and sentences1 is
an actual array
for i in $(seq 1 2); do # No double-quotes, we *want* seq's output to be spli
t
echo "$i" "$sentence" # Double-quotes for safety
done
done
答案2
我不知道是什麼原因,但 irc://freenode/bash 提供了解決方案
while IFS=, read -ra items; do
for item in "${items[@]}"; do
for i in {1..3}; do
printf '%d %s\n' "$i" "$item"
done
done
done <<< "Hello World,Questions,Answers"
列印正確。