为什么 echo "$@" 不显示脚本名称但显式迭代会显示?

act*_*nda 9 bash

请考虑脚本 foo.bash

#!/bin/env bash

echo "$@"
echo

for x in "${@:0:$# + 1}" ; do
    echo "$x"
done
Run Code Online (Sandbox Code Playgroud)

然后./foo.bash a b c给出输出

a b c

./foo.bash
a
b
c
Run Code Online (Sandbox Code Playgroud)

据我了解文档,@保存位置参数,所以输出echo "$@"对我来说很有意义。

但是为什么for循环会打印脚本名称?

编辑:

我在 Windows 上使用 Git BASH,echo $BASH_VERSION产生 4.4.23(1)-release

anu*_*ava 9

此行为特定于版本bash4+。

按照 man bash

@ 扩展到位置参数,从 1 开始。也就是说,"$@"相当于"$1" "$2" "$3"...

然而:

${parameter:offset:length} 子串扩展。从 offset 指定的字符开始,最多扩展到参数值的 length 个字符。 如果参数是@、下标为@或的索引数组*或关联数组名称,则结果不同,如下所述。如果省略length,则扩展为参数值的子字符串,从offset 指定的字符开始,一直延伸到值的末尾。length 和 offset 是算术表达式(参见下面的 ARITHMETIC EVALUATION)。 如果参数是@,则结果是length从 开始的位置参数offset。如果参数是下标为@或的索引数组名称*,结果是以 开头的数组的长度成员${parameter[offset]}

除非使用位置参数,否则子字符串索引是从零开始的,在这种情况下,索引默认从 1 开始。 如果offset为 0,并且使用了位置参数,则以$0列表为前缀

所以如果你使用:

"${@:0}"
Run Code Online (Sandbox Code Playgroud)

这也将包括 $0

但是如前所述:

"$@"
Run Code Online (Sandbox Code Playgroud)

将从位置一开始。

PS:请注意,在以前的bash版本中,行为是不同的,"${@:0}"不会包含$0.

  • @anubhava 确实,谢谢。如果您也引用了这一点,您的答案会更完整:) 这部分甚至表明 `${@:offset:length}` 是与 `$@` 本身完全分开的特殊语法。 (3认同)
  • 这并不是无证的。本节暗示了“如果省略 length,则扩展为从 offset 指定的字符开始的参数值的子字符串”的行为。因此,当“offset”为“0”时,它将扩展为“$0 $1 $2...” (2认同)