Bash 参数扩展

Bash 参数扩展

我读过/被告知,在 Bash(我的例子是 4+)中,字符串上可用的所有参数扩展函数都可以在数组上使用。今天我试图设置一个类似于数组弹出的函数。我使用了类似于以下语法的内容:

declare -a arr=( 0 1 2 3 4 5 )
arr=( ${arr[@]:0:(-1)} )

出乎意料的是,Bash 抱怨道:

-bash: (-1): substring expression < 0

当我使用字符串执行此操作时,语法按预期工作。例如:

var="see spot run"
var="${var:0:(-1)}"
echo "$var"
  see spot ru

我知道对于数组我可以这样做(并且我测试了它的工作原理):

declare -a arr=( 0 1 2 3 4 5 )
arr=( ${arr[@]:0:((${#arr[@]}-1))} )
echo ${arr[@]}
    0 1 2 3 4

问题是,如果所有字符串参数扩展都适用于数组,为什么 (-1) 语法不能按我的预期工作?我是否只是在这里忽略了一些简单的东西,或者是否有一些更深层次的东西在起作用?

答案1

这个问题的答案似乎是并非所有字符串参数扩展都适用于数组。在查看评论并阅读 Bash 参考手册(由 don_crissti 提供的链接,谢谢)之后,有一个关于子字符串扩展的负索引的警告。正如 Bash 手册中所述(外壳参数扩展):

${parameter:offset:length}

这称为子串扩展。它扩展到长度从指定字符开始的参数值的字符抵消。如果参数是、下标为或 的@索引数组或关联数组名称,则结果会有所不同,如下所述。@*

...

如果参数是索引数组名称,下标为@*,则结果为长度以 开头的数组成员${parameter[offset]}。负数抵消相对于比指定数组的最大索引大一的值。如果出现以下情况,则为扩展错误:长度计算结果为小于零的数字。

正如 don_crissti 所指出的,这里完成的长度评估不是参考字符串/子字符串的长度,而是在分配长度属性期间执行的评估。正如 don_crissti 的示例所示:

a=2
printf %s\\n "${arr[@]:3:(a+1)}"

如果长度赋值 (a+1) 的算术评估部分产生负值,或者像我的情况一样,该值本身作为负数静态传递,则这是一个扩展错误。话虽这么说,以下两种情况都会导致扩展错误:

declare -a arr=( 0 1 2 3 4 5 )
# length evaluates to (-1)
a=2
printf %s\\n "${arr[@]:3:(a-3)}"
  -bash: (a-3): substring expression < 0

# or length is assigned as (-1)
arr=( ${arr[@]:0:(-1)} )
  -bash: (-1): substring expression < 0

根据 Bash 手册,这在两种情况下都是预期的行为。

相关内容