Bash 扩展之谜

Bash Expansion Mystery

这是一个关于 Whosebug 的非常 "popular" 的主题,不幸的是,我在查看其他问题时未能弄清楚这一点。无论如何,让我们考虑以下情况。 一个函数获取一堆字符串参数,如下所示: some_function "give some" "string arguments" 这个函数做的第一件事是将这些参数放入一个数组中,例如 array[0] 给出 "give some" 而 array[1] 给出 "string arguments"

现在假设我有一个字符串数组 some_array 并想对其调用 some_function。我如何 "transform" 该数组使其工作?

以下是一些不起作用的示例:

function print_args() {
  local arr=( "$@" )
  i=0;
  for item in "${arr[@]}"
  do
    echo "[$i] -> '$item'"
    (( i++ ))
  done
}

echo "example"
print_args "this is" "the desired" "behavior"
echo -e "----------------\n"

some_array=( "\"does NOT\""  "\"seem to\"" "\"work\"" )
stringified_array=$(printf "%s " "${some_array[@]}")
echo "stringified array: [$stringified_array]"

echo "1) passing $some_array"
print_args $some_array
echo -e "---------------------------\n"

echo "2) passing \"$some_array\""
print_args "$some_array"
echo -e "---------------------------\n"

echo "3) passing $stringified_array"
print_args $stringified_array
echo -e "---------------------------\n"

echo "4) passing \"$stringified_array\""
print_args "$stringified_array"
echo -e "---------------------------\n"

这是输出

example
[0] -> 'this is'
[1] -> 'the desired'
[2] -> 'behavior'
----------------

stringified array: ["does NOT" "seem to" "work" ]
1) passing $some_array
[0] -> '"does'
[1] -> 'NOT"'
---------------------------

2) passing "$some_array"
[0] -> '"does NOT"'
---------------------------

3) passing $stringified_array
[0] -> '"does'
[1] -> 'NOT"'
[2] -> '"seem'
[3] -> 'to"'
[4] -> '"work"'
---------------------------

4) passing "$stringified_array"
[0] -> '"does NOT" "seem to" "work" '
---------------------------

我想我理解 1) 和 2) 并且只是出于绝望而尝试了它们。我相信我也理解 4)。现在我的大问题是我不明白 3) 到底是怎么回事,更重要的是我如何 "stringify" 我的数组以实现我想要的。这里有一个重要的注意事项是,我想尝试 避免使用 eval.

谢谢!

你可能认为你说的是​​ 3):

print_args "does NOT" "seem to" "work"

但实际上 3) 等同于:

print_args '"does' 'NOT"' '"seem' 'to"' '"work"'

这是因为未加引号的参数变量 $stringified_arrayIFS 之前被拆分成单词 它被传递给函数。字符串中的双引号只是字符串的一部分,not 不会引用空格。

尝试通过修改示例代码中的第 16-#17 行来查看会发生什么:

16c16
< stringified_array=$(printf "%s " "${some_array[@]}")
---
> stringified_array=$(printf "%s#" "${some_array[@]}")
17a18
> IFS=#

通过将 IFS 分配给未出现在您的字符串中的分隔符,您将 能够安全地 stringify 你的数组,尽管会有其他解决方案 不对数组进行字符串化。
希望这有帮助。