Невозможно представить себе язык программирования, который не поддерживал бы массивов. Под массивами обычно подразумеваются упорядоченные списки строк, символов или любых других объектов. Неважно как они реализованы в большинстве языков программирования, они помогают лучше управлять данными.
Язык сценариев Bash тоже имеет свои возможности работы с массивами. В этой статье мы рассмотрим как работают массивы Bash, как их создавать и использовать. В некоторых случаях это очень удобно.
Содержание статьи
Массивы Bash
Массивы оболочки Bash работают почти так же, как и в других языках программирования. Перед тем как вы сможете использовать массив, его нужно объявить. Это можно сделать несколькими способами, первый из них - это использование команды оболочки declare:
declare -a имя_массива
Но необязательно делать именно так, вы можете сразу начать задавать элементы массива по нужным номерам:
имя_массива[XX] = значение
Здесь XX обозначает индекс массива. Еще один удобный способ создавать массивы строк Bash - это просто перечислить все элементы в круглых скобках:
имя_массива=( элемент_1 элемент_2 элемент_3 ... )
Или вы можете сразу задать индекс массива для каждого из элементов:
имя_массива=( [XX]=значение [XX]=значение . . . )
Также можно прочитать значения для массива из клавиатуры или другого источника ввода:
read -a имя_массива
При вводе элементов массива они должны быть разделены символом пробела. Для получения значений элементов массива используйте синтаксис фигурных скобок, обратите внимание, что нумерация элементов массива, как и в большинстве языков начинается с нуля:
${имя_массива[XX]}
Это все основные моменты, которые будут вам полезны при использовании массивов, теперь нам осталось рассмотреть основные примеры, чтобы вам было более понятно как все это работает.
Примеры использования массивов Bash
Теперь рассмотрим примеры массивов bash. Сначала нам нужно создать массив, который мы будем использовать для примеров, на мой взгляд будет проще использовать синтаксис с круглыми скобками. Вообще, массивы используются в скриптах, но мы будем их применять прямо в оболочке Bash. Для начала так будет проще. Создаем массив:
array=(первый второй третий четвертый пятый)
Теперь попытаемся вывести один из элементов массива по его индексу:
echo ${array[1]}
$ echo ${array[2]}
$ echo ${array[0]}
Чаще всего используются массивы строк Bash, но иногда могут встречаться и цифры. Помните про нумерацию? Индексы элементов массива начинаются с нуля. Для вывода значения элемента по индексу можно использовать и немного другой синтаксис:
echo ${array:0}
Вы можете вывести все элементы:
echo ${array[@]}
Все элементы, начиная с номера 1:
echo ${array[@]:1}
Вывести все элементы которые находятся в диапазоне от 1 до 4:
echo ${array[@]:1:4}
Чтобы узнать длину первого элемента выполните:
echo ${#array[0]}
А посмотреть количество элементов массива Bash можно таким же синтаксисом:
echo ${#array[@]}
Кроме всего прочего, вы можете заменить одни символы в определенном элементе массива или во всем массиве на другие. Для этого используйте:
echo ${array[@]//р/Р}
В некоторых случаях, для перебора элементов массива очень удобно использовать циклы. На этот раз сделаем небольшой скрипт:
#!/bin/bash
array=(первый второй третий четвертый пятый)
for i in ${array[@]}
do
echo $i
done
Внутри цикла вы можете делать со значением элемента все, что вам нужно. Как я уже писал выше, вы можете прочитать значения для массива с помощью функции read:
#!/bin/bash
echo "Введите элементы массива:"
read -a array
echo "Результат:"
for i in ${array[@]}
do
echo $i
done
Как и в любом другом варианте, вам нужно, чтобы все элементы были разделены пробелом. Точно так же можно присвоить массиву результат выполнения команды. Например, сохраним список файлов, полученный от ls:
array=( $(ls /) )
Усложним задачу и сделаем скрипт, который будет выводить все файлы из указанной директории, которые имеют права доступа 755:
vi lsperm.sh
#!/bin/bash
ERR=27
EXT=0
if [ $# -ne 1 ]; then
echo "Используйте: $0 <путь>"
exit $ERR
fi
if [ ! -d $1 ]; then
echo "Каталог $1 не существует"
exit $ERR
fi
temp=( $(find $1 -maxdepth 1 -type f) )
for i in "${temp[@]}"
do
perm=$(ls -l $i)
if [ `expr ${perm:0:10} : "-rwxr-xr-x"` -eq 10 ]; then
echo ${i##*/}
fi
done
exit $EXT
Теперь проверим наш скрипт на папке /bin. Но перед этим нужно дать ему права на выполнение:
chmod u+x ./lsperm.sh
$ ./lsperm.sh
Как видите, все работает. Кроме номеров, в качестве индексов для массивов можно использовать строки. Такие массивы Bash называются ассоциативными и поддерживаются они начиная с четвертной версии Bash. Для создания ассоциативного массива используется declare с опцией -A:
declare -A assoc_array
assoc_array[first]=первый
$ assoc_array[last]=последний
echo ${assoc_array[first]}
$ echo ${assoc_array[last]}
Несмотря на то что Bash поддерживает только одномерные массивы, мы можем выполнять симуляцию работы с многомерными матрицами с помощью ассоциативных массивов:
declare -A matrix
arr[0,0]=0
$ arr[0,1]=1
$ arr[1,0]=2
$ arr[1,1]=3
echo "${arr[0,0]} ${arr[0,1]}"
Чтобы удалить массив, созданный с помощью declare используйте функцию unset:
unset matrix
Выводы
В этой статье мы рассмотрели как работают массивы Bash в Linux, как их создавать, а также как использовать. Если разобраться, то здесь нет ничего очень сложного, а массивы могут стать очень важным элементов ваших скриптов.
вообще красавчик, зачет! четка статейка! to be continued
Спасибо
Очередной пример того, как НЕ надо делать.
Вот это array=( $(ls /) ) как будет работать, если среди файлов окажутся те, которые содержат пробел в имени?
funt, предложите правильный вариант
А то, что вы отписали, тоже совершенно ни о чём
Ну, на то есть простое решение, например:
array=( "$(ls -1 /)" )
или
IFS=''; array=( "$(ls -1 /)" ) # это уже под sh, а на bash, с какой-то там версии, работает и array=( $(ls /) )
echo ${array:0}
это эквивалент
echo ${array[0]:0}
т.е. вывод всех символов нулевого элемента массива, а не сам нулевой элемент.
В последнем примере, где речь идет о многомерных массивах, у меня есть вопросы, и если кто-то обьяснит - буду признателен.
(для наглядности, скопирую сюда)
declare -A matrix
arr[0,0]=0
$ arr[0,1]=1
$ arr[1,0]=2
$ arr[1,1]=3
echo "${arr[0,0]} ${arr[0,1]}"
1. Почему мы обьявляем declare -A matrix, когда используем массив с именем "array"?
2. Так же, коммандой echo "${arr[0,0]} ${arr[0,1]}" мы подразумеваем, что нам выведет на экран значение елементов [0,0] и [0,1] (то есть 0, и 1), но на скриншоте видно, что нам выводит два последних значения (2 и 3).
Заранее благодарен за ответ.
В предведущем комментарии доспустил ошибку
"когда используем массив с именем "array"?"
имел ввиду
когда используем массив с именем "arr"?
Как добавить в массив результат команды ls -l. Но чтобы элементами массива были строки, а не слова разделенные пробелом
array=( $(ls -l /) ) работает, но элементами массива становятся слова, разделенные пробелом.
А мне надо, чтобы каждая строка была элементом массива?
Ха ха!! Нашел!
mapfile -t array < <(ls -l);
"имя_массива=( элемент_1, элемент_2 элемент_3 ... )"
Запятую уберите.
"Вывести все элементы которые находятся в диапазоне от 1 до 4:
echo ${array[@]:1:4}"
Не в диапазоне от 1 до 4, а 4 элемента, начиная с 1.