为什么 `for in` 不能在 bash 中直接拆分字符串?
Why can `for in` not split string directly in bash?
例如:
# 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中直接拆分字符串? case 1和case 2有什么区别?
如果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='*'
,例如,字符串拆分会将 *
字符替换为文件列表当前目录。
分词是不带引号的参数扩展(以及不带引号的命令扩展)中的一项功能。这不是 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
例如:
# 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中直接拆分字符串? case 1和case 2有什么区别?
如果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='*'
,例如,字符串拆分会将 *
字符替换为文件列表当前目录。
分词是不带引号的参数扩展(以及不带引号的命令扩展)中的一项功能。这不是 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