bash脚本和zsh shell中数组的行为(起始索引为0还是1?)

21

我需要有关Shell脚本中数组行为的解释:

假设给定以下内容:

arber@host ~> ls
fileA fileB script.sh

现在我可以执行以下命令:

arber@host ~> ARR=($(ls -d file*))
arber@host ~> echo ${ARR[0]}          # start index 0

arber@host ~> echo ${ARR[1]}          # start index 1
fileA
arber@host ~> echo ${ARR[2]}          # start index 2
fileB

但是当我通过 script.sh 进行此操作时,其行为不同(起始索引为0):

arber@host ~> cat script.sh
#!/bin/bash
ARR=($(ls -d file*))

# get length of an array
aLen=${#ARR[@]}

# use for loop read all items (START INDEX 0)
for (( i=0; i<${aLen}; i++ ));
do
  echo ${ARR[$i]}
done

这里是结果:

arber@host ~> ./script.sh
fileA
fileB

我使用Ubuntu 18.04 LTS和zsh。有人可以解释一下这是什么吗?


5
将你的数组填充为arr=(file*),并从index=0开始。 - anubhava
2
在你的交互式 shell 中,type ls 会输出什么? - that other guy
7
你是否在使用 zsh?在 bash 中,数组是从零开始的;而在 zsh 中,数组则是从一开始的。 - chepner
3
根据执行方法和shebang,您的脚本肯定是由bash来执行的,但是您的命令行示例表明您正在使用zshecho $ARR 输出 fileA 还是 fileA fileB - chepner
1
@Arber,zsh是完全不同的shell,它甚至不会尝试与bash兼容(或者遵循POSIX sh规范,除非明确为此目的设置模式--尽管后者对于这个问题来说无关紧要,因为数组不是POSIX功能)。 - Charles Duffy
显示剩余7条评论
2个回答

45

简而言之:

  • bash 数组索引始于 0(始终如此)
  • zsh 数组索引始于 1(除非设置了 选项 KSH_ARRAYS

为了始终获得一致的行为,请使用:

${array[@]:offset:length}

解释

对于在bashzsh中都能工作的代码,你需要使用offset:length语法,而不是[subscript]语法。

即使是zsh专用的代码,你仍然需要这样做(或者使用emulate -LR zsh),因为zsh的数组下标基础是由KSH_ARRAYS选项确定的。

例如,要引用数组中的第一个元素:

${array[@]:0:1}

在这里,array[@]表示所有元素,0是偏移量(始终从0开始),1是所需元素的数量。

谢谢,要引用第一个 zsh 数组元素,如果您不需要两个 shell 之间的兼容性,我会使用 $ar[1] 来减少打字,而不是您的解决方案。 - Timo
2
这通常是正确的,但取决于zsh的KSH_ARRAYS选项的值。 - Tom Hale

13

Bash中的数组从零开始索引, 而zsh中的数组从一开始索引

但是在这种简单情况下,您不需要使用索引。循环${array[@]} 在两者中都可以使用:

files=(file*)
for f in "${files[@]}"; do
    echo "$f"
done

在zsh中,你也可以使用$files代替"${files[@]}",但在Bash中这不起作用。(并且有一个轻微的差异,它会删除空数组元素,但你在文件名中不会得到任何元素。)
此外,不要使用$(ls file*),如果文件名中有空格,它会出错(参见BashGuide上的WordSpliting),而且根本没有用。Shell完全可以自己生成文件名。实际上,这就是发生的情况:shell找到所有与file*匹配的文件名,将它们传递给lsls仅仅将它们打印出来以供shell读取和处理。

"...再次将它们打印到shell中",这将对引号进行删除并在空格字符(或$IFS)上进行拆分,两者都可能导致错误或意外结果。 - Kusalananda
@Kusalananda,这正是我所说的有空格文件名的问题,但我懒得每次都打免责声明。而且我认为它不会去掉引号。当然,还有通配符和单词/字段拆分。 - ilkkachu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接