Официальная возможность получить лицензионный софт бесплатно.
Giveaway of the Day
Это не реклама!

Щелкните для получения прогноза по Биробиджану


пятница, 17 июля 2015 г.

bash: дополнение по работе с массивами

Новый ABSG (версия 10 от 20140310) можно взять на TLDP, источник выглядит вполне официально. Даю ссылку на страницу, а не на конкретный файл, поскольку там можно скачать ABSG в нескольких вариантах. Я себе скачиваю PDF и "плоский" (всё в одном файле) html, но кому-то может понравится и другой из предложенных вариантов.

Теперь собственно о массивах. Более подробно можно посмотреть в ABSG-10 на стр 869



В отличие от обычных массивов, массивы в bash:
1. только одномерные (на данный момент)

2. состоят из нетипизированных элементов
Можно в одном массиве смешивать числа и строки

3. являются "частично ассоциативными"
Что такое ассоциативный массив? Это массив, в котором индекс элемента не обязательно является его номером. Ближе всего к нему список "ключ=значение", который используется во всевозможных конфигах.
Ну, например:

[список]
няш=мяш
годлум=Яценюк
главстерх=Путин


Тогда у массива СПИСОК нет элементов с номерами, но в нем есть:

список[няш]=мяш
список[главстерх]=Путин
список[годлум]=Яценюк


Разумеется, ничто не мешает в левом столбце использовать числа, но в ассоциативном массиве это будут просто названия ключей, состоящие только из цифр. Иногда с этим возникают проблемы, с пониманием разницы между числом и группой цифр, поэтому попробую сказать иначе:

число 65 в двоичном виде выглядит как: 00000000 01000001
название "65" выглядит как: 00110110 00110101
Таблица ASCII вам в помощь.

Тогда что же я понимаю под "частично ассоциативным? Проведем эксперимент:
(во всех примерах ниже команда echo выводит количество элементов массива, массив целиком и три его элемента)

$ unset area;area[good]=22;area[bad]=66;area[51]=UFOs; echo ${#area[@]} ${area[@]} ${area[51]} good ${area[good]} bad ${area[bad]}

2 66 UFOs UFOs good 66 bad 66

$ unset area;area["good"]=22;area["bad"]=66;area[51]=UFOs; echo ${#area[@]} ${area[@]} ${area[51]} good ${area["good"]} bad ${area["bad"]; }


2 66 UFOs UFOs good 66 bad 66


Видно, что, несмотря на явное задание трёх элементов - good, bad и 51 - в массиве содержится только два значения, причем по индексам good и bad выдается одно и то же, последнее, несмотря на присваивание разных. Добавление кавычек ситуацию не улучшило. Следовательно, индекс, заданный не цифрами, считается нулём. Но почему?
Думаю, потому, что буквенный индекс воспринимается как имя переменной, содержащей число:

$ good=3;unset area;area["good"]=22;area["bad"]=66;area[51]=UFOs; echo ${#area[@]} ${area[@]} ${area[51]} good ${area["good"]} bad ${area["bad"]}

3 66 22 UFOs UFOs good 22 bad 66


Видно, что после инициализации переменной $good, в массиве стало три элемента. И никакой мистики. Еще стоит обратить внимание на то, что между элементами 3 и 51 нет ничего - элементы с 4 по 50 отсутствуют.

Потому я и назвал массивы bash частично ассоциативными - в качестве индекса может использоваться только число, но числа не обязаны идти последовательно. Приятно, но печально.

Теперь достаём из шляпы кролика: начиная с bash версии 4, есть возможность создавать именно ассоциативные, а не частично ассоциативные массивы. Для этого служит оператор declare -A (ABSG-10, p.552). Слегка изменим пример:

unset area;declare -A area;area[good]=22;area[bad]=66;area[51]=UFOs; echo ${#area[@]} ${area[@]} ${area[51]} good ${area[good]} bad ${area[bad]}

3 66 UFOs 22 UFOs good 22 bad 66


И теперь можно обращаться к элементам массива по именам, хотя лично я не совсем понял способ сортировки: да, "b" идет перед "g", но почему "51" оказалось между ними?

Теперь о еще более приятном. Как я понял, массивы автоматически сортируются по именам ключей:

$ unset area;area[2]=22;area[5]=66;area[51]=UFOs; echo =1=${area[@]}=1= ; area[3]=33; echo =2=${area[@]}=2=; area[3]=""; echo =3=${area[@]}=3=

=1=22 66 UFOs=1=
=2=22 33 66 UFOs=2=
=3=22 66 UFOs=3=


Выше в массив изначально добавлено 3 элемента с индексами 2, 5 и 51. Потом я добавляю элемент с индексом 3 и он занимает свое законное место между вторым и пятым. Затем очищаю третий элемент и он исчезает из массива.
Это открывает прекрасные возможности по обработке данных в циклах и т.д., то есть там, где не всегда известно количество обрабатываемых элементов, или где элементы должны создаваться/удаляться динамически.
Разумеется, отсутствие типизации и предварительного описания переменных может привести к трудноуловимым ошибкам, скажем, из-за опечаток, поэтому использовать такое надо с осторожностью, чтобы массив "/ - f m r r" не превратился в rm -rf /...

Комментариев нет:

Отправить комментарий

Пожалуйста, воздержитесь от грубостей и персональных нападок.
Я не против матерщины, но она должна быть уместной и использоваться для выражения эмоций, а не в качестве основного средства выражения мыслей.