Поведение массивов в сценариях bash и оболочке zsh (индекс начала 0 или 1?) - PullRequest
0 голосов
/ 19 мая 2018

Мне нужно объяснение о следующем поведении массивов в сценариях оболочки:

Представьте, что дано следующее:

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 , он ведет себя по-другому (Start Index = 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 .Может кто-нибудь объяснить это?

Ответы [ 2 ]

0 голосов
/ 26 мая 2019

TL; DR:

  • bash индексация массива начинается с 0 (всегда)
  • zsh индексация массива начинается с 1 (если опция KSH_ARRAYS установлена)

Чтобы всегда получить согласованное поведение, используйте:

${array[@]:offset:length}

Объяснение

Для кода, который работает как bash, так и zsh, вам нужно использовать синтаксис offset:length вместо синтаксиса [subscript].

Даже для zsh -только кода, вы 'Мне все еще нужно будет сделать это (или использовать emulate -LR zsh), поскольку основа подписки массива zsh определяется параметром KSH_ARRAYS.

Например, для ссылки на первый элемент в массиве:

${array[@]:0:1}

Здесь array[@] - все элементы, 0 - смещение (которое всегда основано на 0), а 1 - желаемое количество элементов.

0 голосов
/ 20 мая 2018

Массивы в Bash индексируются с нуля , а в zsh индексируются с одного .

Но вам не нужны индексы для простогоСлучай использования, такой как этот.Цикл по ${array[@]} работает в обоих случаях:

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

В zsh вы также можете использовать $files вместо "${files[@]}", но это не работает в Bash.(И есть небольшая разница в том, что он отбрасывает пустые элементы массива, но вы не получите ни одного из имен файлов.)


Кроме того, не используйте $(ls file*), он сломается, если у вас естьимена файлов с пробелами (см. WordSpliting в BashGuide ) и с самого начала совершенно бесполезны.

Оболочка вполне способна самостоятельно генерировать имена файлов.Вот что на самом деле происходит: оболочка находит все файлы с именами, соответствующими file*, передает их в ls, а ls просто выводит их снова для чтения и обработки оболочкой.

...