为什么`for in`不能直接在bash中拆分字符串?

时间:2017-05-27 16:07:16

标签: bash quoting

例如:

# case 1
for i in "a b c"; do echo -n $i| od -b; done
# case 2
v="a b c"; for i in $v; do echo -n $i| od -b; done

输出:

0000000 141 040 142 040 143
0000005
0000000 141
0000001
0000000 142
0000001
0000000 143
0000001

为什么for in不能直接在bash中拆分字符串?案例1和案例2之间有什么区别?

2 个答案:

答案 0 :(得分:3)

如果for循环自动执行字符串拆分,这将意味着以下代码是不可能的:

# this should be (and currently is!) two lines, not four.
for message in "hello world" "goodbye world"; do
  echo "$message"
done

或者,对于更现实的例子,请考虑:

shopt -s nullglob
echo "Listing length in lines of files with spaces in their names from My Documents"
for file in "My Documents"/*; do
  printf '%s\t%s lines\n' "$file" "$(wc -l <"$file")"
done
echo "Done"

...在这种情况下,执行字符串拆分的for循环会将My视为单独的文件名,而不是将文件名保存在一起。

如果您想安全将字符串拆分为多个元素,请使用read -a,而不是字符串拆分:

v='a b c'
read -r -a v_a <<<"$v"
for i in "${v_a[@]}"; do
  printf '%s' "$i" | od -b
done

即使对于字符串拆分会导致的输入值,这也能正常工作 - 例如,考虑v='*',其中字符串拆分会将*字符替换为当前文件列表。目录

答案 1 :(得分:2)

单词拆分是不带引号的参数扩展(以及不带引号的命令扩展)中的一项功能。它不是for循环的功能。

  • 不带引号的变量在for循环中拆分字符串,因为不带引号的变量在几乎所有地方都会分割字符串。

  • for循环不直接拆分字符串,因为它们根本不拆分字符串。这不是循环的责任。

这里有三个例子,每个例子都有一个文字字符串,一个引用变量和一个不带引号的变量。您可以看到没有特殊情况,所有拆分都是由于未加引号的参数扩展:

var="a b c"

command "a b c" "$var" $var
                        ^-- Only thing that splits

array=("a b c" "$var" $var)
                        ^-- Only thing that splits

for s in "a b c" "$var" $var
do ...                  ^-- Only thing that splits