Behavior of Arrays in bash scripting and zsh shell (Start Index 0 or 1?)

TL;DR:

  • bash array indexing starts at 0 (always)
  • zsh array indexing starts at 1 (unless option KSH_ARRAYS is set)

To always get consistent behaviour, use:

${array[@]:offset:length}

Explanation

For code which works in both bash and zsh, you need to use the offset:length syntax rather than the [subscript] syntax.

Even for zsh-only code, you'll still need to do this (or use emulate -LR zsh) since zsh's array subscripting basis is determined by the KSH_ARRAYS option.

Eg, to reference the first element in an array:

${array[@]:0:1}

Here, array[@] is all the elements, 0 is the offset (which always is 0-based), and 1 is the number of elements desired.


Arrays in Bash are indexed from zero, and in zsh they're indexed from one.

But you don't need the indices for a simple use case such as this. Looping over ${array[@]} works in both:

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

In zsh you could also use $files instead of "${files[@]}", but that doesn't work in Bash. (And there's the slight difference that it drops empty array elements, but you won't get any from file names.)


Also, don't use $(ls file*), it will break if you have filenames with spaces (see WordSpliting on BashGuide), and is completely useless to begin with.

The shell is perfectly capable of generating filenames by itself. That's actually what will happen there, the shell finds all files with names matching file*, passes them to ls, and ls just prints them out again for the shell to read and process.