令人惊讶的阵列扩展行为

Nor*_*wap 12 arrays bash shell ifs

(!!)对以下示例中标记的行感到惊讶:

log1 () { echo $@; }
log2 () { echo "$@"; }

X=(a b)
IFS='|'

echo ${X[@]}   # prints a b
echo "${X[@]}" # prints a b
echo ${X[*]}   # prints a b
echo "${X[*]}" # prints a|b
echo "---"
log1 ${X[@]}   # prints a b
log1 "${X[@]}" # prints a b
log1 ${X[*]}   # prints a b
log1 "${X[*]}" # prints a b (!!)
echo "---"
log2 ${X[@]}   # prints a b
log2 "${X[@]}" # prints a b
log2 ${X[*]}   # prints a b
log2 "${X[*]}" # prints a|b
Run Code Online (Sandbox Code Playgroud)

以下是我对行为的理解:

  • ${X[*]}${X[@]}扩大到a b
  • "${X[*]}" 扩展到 "a|b"
  • "${X[@]}" 扩展到 "a" "b"
  • $*$@具有相同的行为${X[*]}${X[@]},除了它们的含量为程序或函数的参数

这似乎是由bash手册证实的.

log1 "${X[*]}"因此,在该行中,我希望引用的表达式扩展为"a | b",然后传递给log1函数.该函数有一个显示的字符串参数.为什么会发生其他事情?

如果您的答案得到手动/标准参考的支持,那就太酷了!

che*_*ner 7

IFS不仅用于连接元素${X[*]},还用于分割不带引号的扩展$@.对于log1 "${X[*]}",发生以下情况:

  1. "${X[*]}"扩展到a|b预期,因此$1设置为a|b内部log1.
  2. $@(未引用)展开时,结果字符串为a|b.
  3. 不带引号的扩展经过分词|作为分隔符(由于全局值IFS),因此echo接收两个参数,ab.

  • 始终使用引用的扩展.这就是答案.你的`log1`函数完全不正确.`log2`是正确的形式. (2认同)
  • 更准确地说,总是引用`$ @`.(有些情况下你可能会故意留下`$*`或其他参数不引用,但`$ @`*存在*被引用;它与`$*`相同.) (2认同)

cho*_*oba 5

那是因为$IFS设置为|:

(X='a|b' ; IFS='|' ; echo $X)
Run Code Online (Sandbox Code Playgroud)

输出:

a b
Run Code Online (Sandbox Code Playgroud)

man bash 说:

IFS内部字段分隔符,用于扩展后的单词拆分...