Подсчет массива в два раза превышает ожидаемое количество элементов

Почему bash кажется, считает слова в массиве, а не количеством элементов?

 touch '1 red' '2 orange' '3 yellow' # Three filenames, each of two words files=( * ) # Get the set of files echo "#files is ${#files}" for (( i=0; i <= ${#files}; i++ )) do printf "%d\t%s\n" $i "${files[$i]}" done 

Результат из этого кажется «неправильным». Во-первых, ${#files} содержит 5 , показывая, что в ${files[@]} содержится шесть элементов. Тем не менее, только элементы 0 , 1 и 2 из ${files[@]} содержат любые данные и содержат правильные имена файлов:

 #files is 5 0 1 red 1 2 orange 2 3 yellow 3 4 5 

Я ожидал бы, что ${files[@]} будет содержать шесть слов 1 , red , 2 , orange , 3 и yellow или ${#files} равными 2 . Не этот смешанный сценарий.

Может ли кто-нибудь пролить свет на это для меня, пожалуйста?

${#files} – это длина первого элемента массива, т. е. длина 1 red . Это пять.

Из руководства :

$ {# name [subscript]} расширяется до длины $ {name [subscript]}. Если индексом является «@» или «*», разложение – это количество элементов в массиве. […]
Ссылка на переменную массива без индекса эквивалентна привязке к индексу 0.

Итак, ${#files} = ${#files[0]} . Но ${#files[@]} или ${#files[*]} дают количество элементов в массиве.

(Это не имеет никакого отношения к числу слов, хотя если вы разворачиваете ${files[*]} без кавычек, вы получаете обычное слово, разделяющее все значения.)

Измените ${#files}" на ${#files[@]}"

Вы получаете 5 из ${#files}" потому что это первый файл.
Эквивалентен ${files[0]} , который называется «1 красный».
Эта строка содержит 5 символов.

Петля не работает для одной и той же проблемы, она итерации от 1 до 5.
Однако элементы 3, 4 и 5 просто нулевые (не заданы).