TL;DR:
bashl'indicizzazione dell'array inizia da0(sempre)zshl'indicizzazione dell'array inizia da1(a meno che l'opzioneKSH_ARRAYSè impostato)
Per ottenere sempre un comportamento coerente, usa:
${array[@]:offset:length}
 Spiegazione
 Per il codice che funziona sia in bash e zsh , devi utilizzare il offset:length sintassi anziché [subscript] sintassi.
 Anche per zsh -only code, dovrai comunque farlo (o utilizzare emulate -LR zsh ) da zsh la base di indicizzazione dell'array di è determinata da KSH_ARRAYS opzione.
Ad esempio, per fare riferimento al primo elemento in un array:
${array[@]:0:1}
 
 Qui, array[@] sono tutti gli elementi, 0 è l'offset (che sempre è in base 0) e 1 è il numero di elementi desiderati.
Gli array in Bash sono indicizzati da zero e in zsh sono indicizzati da uno.
 Ma non hai bisogno degli indici per un semplice caso d'uso come questo. Loop su ${array[@]} funziona in entrambi:
files=(file*)
for f in "${files[@]}"; do
    echo "$f"
done
 
 In zsh puoi anche usare $files invece di "${files[@]}" , ma non funziona in Bash. (E c'è la leggera differenza che elimina gli elementi dell'array vuoti, ma non ne otterrai alcuno dai nomi dei file.)
 Inoltre, non utilizzare $(ls file*) , si romperà se hai nomi di file con spazi (vedi WordSpliting su BashGuide), ed è completamente inutile per cominciare. 
 La shell è perfettamente in grado di generare nomi di file da sola. Questo è effettivamente ciò che accadrà lì, la shell trova tutti i file con nomi corrispondenti a file* , li passa a ls e ls semplicemente li stampa di nuovo affinché la shell li legga e li elabori.