9

我需要解释 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。有人可以解释一下吗?

4

2 回答 2

20

TL;博士:

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

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

${array[@]:offset:length}

解释

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

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

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

${array[@]:0:1}

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

于 2019-05-26T07:55:22.187 回答
10

Bash 中的数组从零开始索引在 zsh 中它们从一开始索引

但是对于这样的简单用例,您不需要索引。循环${array[@]}在两种情况下都有效:

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

在 zsh 中,您也可以使用$files而不是"${files[@]}",但这在 Bash 中不起作用。(还有一点不同,它会丢弃空数组元素,但你不会从文件名中得到任何东西。)


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

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

于 2018-05-20T10:16:23.730 回答