![Bash 参数扩展](https://linux22.com/image/142386/Bash%20%E5%8F%82%E6%95%B0%E6%89%A9%E5%B1%95.png)
我读过/被告知,在 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 手册,这在两种情况下都是预期的行为。