有没有办法用bash读取数组的最后一个元素?


68

如果我有一个包含5个元素的数组,例如:

[a][b][c][d][e]

使用echo ${myarray[4]}我可以看到它的含义。

但是,如果我不知道给定数组中元素的数量怎么办?有没有办法读取未知长度数组的最后一个元素?即第一个元素从右到左读取任何数组?

我想知道如何用bash做到这一点。


$@不是一个数组(不能下标)。为此,请参阅获取传递给shell脚本的最后一个参数
汤姆·黑尔

Answers:


89

您可以只使用一个负索引 ${myarray[-1]}来获取最后一个元素。您可以为倒数第二个做同样的事情,依此类推。在Bash中:

如果用于引用索引数组元素的下标的值小于零,则将其解释为相对于大于数组最大索引的下标,因此负索引从数组末尾算起,并且索引-1表示最后一个元素。

分配也一样。当说“表达”时,它实际上意味着表达。您可以在其中编写任何算术表达式来计算索引,包括一个使用数组长度${#myarray[@]}显式计算的索引。


2
你可以这样做,在kshzsh也。
贾尼斯,2015年

5
zsh虽然,默认数组是1索引,不同于bashksh他们在哪里0索引。
Stephen Kitt 2015年

2
当然是; 这个问题的简短答案没有改变,但是由于提到了长形式,我认为有必要指出那里行为的差异。
Stephen Kitt 2015年

22
负索引仅在bash 4.3及更高版本中有效。
cuonglm 2015年

10
至少从v10.11.5起,Mac OS X附带的Bash版本仅为3.2,因此在Mac上不起作用。
Doktor J

44

现代bash(v4.1或更高版本)

您可以阅读index的最后一个元素-1

$ a=(a b c d e f)
$ echo ${a[-1]}
f

bash版本4.1-alpha开始,支持使用负索引从最后访问数字索引数组。

较旧的bash(v4.0或更早版本)

您必须从中获取数组长度${#a[@]},然后减去一个以获取最后一个元素:

$ echo ${a[${#a[@]}-1]}
f

由于bash将数组下标视为算术表达式,因此不需要其他符号(例如$((...)))来强制进行算术评估。


最后一个对我不起作用;我正在使用Bash v4.1.2(1):不是打印最后一个项目,而是打印出整个数组。
Alexej Magura

但是,@ cuonglm的答案有效。
Alexej Magura

如果您有资格modern使用某个版本,答案会更好。
Samveen

1
正是使anwser完美所需的东西。
Samveen '17

1
这次真是万分感谢。我之所以使用echo $ {a [$(($ {#a [@]}-1]))},是因为我不知道“ bash将数组下标视为算术表达式”。
布鲁诺·布罗诺斯基

15

bash数组分配,引用,带有负索引的取消设置仅在bash 4.3中添加。在的旧版本中bash,您可以在索引中使用表达式array[${#array[@]-1}]

另一种方法,也可以与旧版本bash(bash 3.0或更高版本)一起使用:

$ a=([a] [b] [c] [d] [e])
$ printf %s\\n "${a[@]:(-1)}"
[e]

要么:

$ printf %s\\n "${a[@]: -1}"
[e]

使用负偏移量时,您需要将与分开:-以免与:-扩展混淆。


1
做到这一点"${a[@]: -1}",它将在中也起作用(除了bashzshksh
尼斯(Janis)2015年

Kornshell文档(www2.research.att.com/sw/download/man/man1/ksh.html)完全指定了它。(尚未检查zshor 的文档,bash但我在所有三个shell中都对其进行了测试。)
Janis 2015年

@Janis:重新阅读bash文档,它也提到了这一点。再次感谢。
cuonglm

4

数组

bash(自bash 3.0+起)中最古老的替代方法是:

$ a=(aa bb cc dd ee)
$ echo "${a[@]:(-1)}   ${a[@]: -1}   ${a[@]:(~0)}   ${a[@]:~0}"
ee   ee   ee   ee

需要使用空格,以避免对(Use Default Values)(使用默认值)的扩展名:加上减号。-"${var:-abc}"

~是一个算术位求反(相当于一补或翻转所有位)。来自man bash:

算术评估

      ! ~         logical and bitwise negation  

由于bash-4.2 +也:

$ echo "${a[-1]}   ${a[(~0)]}"
ee   ee

由于bash 5.0+也:

$ echo "${a[~0]}"
ee

对于所有bash版本(旧bash):

$ echo "${a[   ${#a[@]}-1   ]}"    # spaces added **only** for readability
ee

@

对于位置参数(自bash 2.01起):

$ set aa bb cc dd ee
$ echo "${@:(-1)} ${@:~0} ${@: -1} ${@:$#}   ${!#}"
ee ee ee   ee

所有外壳的便携式解决方案是使用eval:

eval printf '"%s\n"' \"\${$#}\"

您有bash 5+语法参考吗?我~手册中搜索了所有58个实例,但没有看到。
汤姆·黑尔

...以及如何处理$@bash: ${@[@]:(-1)}: bad substitution
汤姆·黑尔

1
是的,有一个man bash参考(请检查@标题处的扩展答案)。@TomHale
艾萨克

1
@阵列(当然,不是完全的阵列在bash),它不接受指数([]个别参数)下标。您需要使用${@:(-1)}或同等学历。检查@标题的扩展条目。@TomHale
艾萨克

-2

您也可以这样做:

$ a=(a b c d e f)
$ echo ${a[$(expr ${#a[@]} - 1)]}

结果:

$ f

您正在执行的操作是获取数组中所有元素的数量,并减去-1,因为要获取所有元素,而不是从数组索引0开始。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.