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

Arb*_*ber 5 linux bash shell ubuntu zsh

我需要对shell脚本中数组的以下行为进行解释:

想象一下,给出了以下内容:

arber@host ~> ls
fileA fileB script.sh
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

但是当我通过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
Run Code Online (Sandbox Code Playgroud)

结果如下:

arber@host ~> ./script.sh
fileA
fileB
Run Code Online (Sandbox Code Playgroud)

我使用Ubuntu 18.04 LTS和zsh。有人可以解释吗?

Tom*_*ale 17

特尔;博士:

  • bash数组索引从0(总是)开始
  • zsh数组索引开始于1(除非设置了选项KSH_ARRAYS

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

${array[@]:offset:length}
Run Code Online (Sandbox Code Playgroud)

解释

对于同时适用于bash和 的代码zsh,您需要使用offset:length语法而不是[subscript]语法。

即使对于zsh-only 代码,您仍然需要这样做(或使用emulate -LR zsh),因为zsh的数组下标基础由KSH_ARRAYS选项决定。

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

${array[@]:0:1}
Run Code Online (Sandbox Code Playgroud)

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

  • 这通常是正确的,但取决于 zsh 的 KSH_ARRAYS 选项的值。 (2认同)

ilk*_*chu 5

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

但您不需要像这样的简单用例的索引。循环${array[@]}工作在两个方面:

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

在zsh中,您也可以使用$files代替"${files[@]}",但这在Bash中不起作用。(并且有一点点区别,它删除了空数组元素,但文件名中没有任何内容。)


另外,$(ls file*)如果文件名带有空格(请参见BashGuide上的WordSpliting),请不要使用,它会中断,并且一开始是完全没有用的。

Shell完全能够自己生成文件名。那实际上就是在那里发生的事情,shell查找所有名称匹配的文件file*,将它们传递给ls,然后ls再次将它们打印出来以供shell读取和处理。