建议使用 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"
可以正确打印。