Вас когда-нибудь удивляло странное поведение массивов в Bash? Только взялись за Bash и уже чувствуете, что с массивами что-то не так? На простых примерах объясняю, почему результат бывает неожиданным — и как перестать наступать на одни и те же грабли.
Если вы хоть раз писали Bash-скрипты, наверняка сталкивались с циклом for. Его синтаксис не слишком очевиден, и сам я немало путался, пока не разобрался с четырьмя главными правилами его работы.
Управлять данными в Bash-скриптах просто — если знаешь, как работают массивы
Разбираемся с массивами шаг за шагом — элемент за элементом.
Давайте рассмотрим частую ошибку. Получаем один и тот же массив — обрабатываем его двумя способами: с кавычками ("${my_arr[@]}") и без кавычек (${my_arr[@]}):
Массив вроде бы с двумя элементами, но почему ${my_arr[@]} без кавычек внезапно выдает четыре? Всё дело в разбиении на слова — именно об этом я сейчас расскажу.
HTG Wrapped 2025: 24 дня вместе с любимыми технологиями
24 дня – наши любимые гаджеты и тех-новинки
Экспресс-курс: как работает for-цикл в Bash
Если вы только осваиваете Bash или просто хотите освежить основы — вот короткое напоминание. А опытные могут перейти к следующей части.
Пример строки: "foo bar". Она взята в кавычки (одинарные или двойные), чтобы пробел не путал Bash. Кавычки дают понять интерпретатору: перед ним одно целое значение.
Bash считает "foo bar" одним словом, если это явно задано контекстом. Здесь «слово» — последовательность символов, которую Bash воспринимает, как один элемент. Чтобы не возникла путаница, буду различать bash-слова и обычные слова.
Вот массив: my_arr=("foo" "bar"). Он состоит из двух значений, которые можно легко перебрать по порядку.
Для этого обычно и применяют цикл for: он «пробегает» по массиву и позволяет делать с каждым элементом что угодно.
«item» — это переменная цикла, или просто итератор. С каждым элементом массива эта переменная обновляется, и вы работаете с ней внутри цикла.
Есть разные способы пройтись по массиву в Bash, но описанный — самый популярный и понятный.
Есть ещё формат обращения к массиву через "${my_arr[*]}". Доберёмся до него чуть позже.
Расширяя параметры, Bash разделяет массив как ему заблагорассудится
Параметр в Bash — по сути, обычная переменная. Расширение параметра (parameter expansion) — это когда Bash подставляет вместо, скажем, $foo её реальное значение во время выполнения скрипта.
Если есть массив my_arr=("one a" "two b"), запись "${my_arr[@]}" превращает его в два отдельных значения: "one a" и "two b". Когда такой массив попадает в цикл for, каждое bash-слово ("one a" и "two b") по очереди становится значением переменной цикла.
Смотрите на примере:
В первом случае (через «@») массив превращается в два отдельных значения: «one a» и «two b».
Во втором (через «*»), все элементы массива сливаются в одну строку с пробелом между ними.
Именно кавычки вокруг массива решают судьбу результата. Стоит их забыть — Bash начнёт делать что-то совсем неожиданное. Вот как это работает.
Разделение на слова: Bash разбивает даже самое целое на части
Как только добавляете кавычки — Bash ведёт себя корректно. А если их опустить?
В обоих вариантах вместо двух получаем аж четыре значения. Почему? Без кавычек Bash сам по себе начинает делить строку на слова по пробелам, табуляциям и переводам строки. И вот "one a" распадается на «one» и «a», а "two b" — на «two» и «b».
$'...' — это особое оформление строки, ANSI-C quoting: Bash превращает спецсимволы (\n, \t и т.д.) в настоящие переносы строк и табуляции. Все такие символы считаются точками разделения слов.
Хотите изменить список этих разделителей? Для этого и существует переменная окружения IFS (Internal Field Separator):
Вот что чаще всего вводит в заблуждение: само «разделение на слова» — это дополнительный шаг Bash. Если посмотреть длину массива через #, она всегда равна реальному числу элементов, а не количеству получившихся слов после разбиения.
3 хитрости Bash, которые обязан знать каждый линуксоид
Раскройте для себя мощь Bash с этими простыми лайфхаками!
Всё, что вы смотрели выше, — разные способы расширения параметров (массива). Только "${my_arr[*]}" (в кавычках и со звездочкой) склеивает весь массив в одну строку, все остальные варианты превращают его в отдельные элементы. Важно: если не использовать кавычки (${my_arr[@]}), Bash обязательно дополнительно разобьёт значения на слова.
Тип
Что получится на выходе...
Будет ли Bash разбивать на слова?
"${my_arr[@]}"
Каждый элемент массива отдельно (Bash-слова)
Нет
"${my_arr[*]}"
Вся коллекция элементов склеена в одну строку
Нет
${my_arr[@]}
Каждый элемент, но Bash разбивает их на части
Да
${my_arr[*]}
Тоже элементы разбиты, как пожелает Bash
Да
Байка про слова в Bash: это непрерывная последовательность символов, вовсе не то же самое, что «слова» в человеческом смысле.
Заметили? Результаты ${my_arr[@]} и ${my_arr[*]} без кавычек одинаково дробятся Bash на кусочки.
Подпишитесь на рассылку — и массивы Bash наконец перестанут вас пугать!
Подпишитесь на рассылку — и массивы Bash наконец перестанут вас пугать!
В конце концов: чаще всего вам нужен именно "${my_arr[@]}" (в кавычках). Так Bash ведёт себя предсказуемо. Пропустите кавычки — цикл for вполне может «сломать» ваши данные. Учитывайте это правило при обработке массивов!
Те же самые принципы действуют для переменных $@ и $* — их используют при передаче аргументов функциям или скриптам.
8 трюков для Linux-оболочки, которые перевернут ваше понимание Bash
Оболочка — это не только команды. Узнайте, как Bash обрабатывает ваши строки и помогает писать более чистые, безопасные скрипты!
Если вам понравилась эта статья, подпишитесь, чтобы не пропустить еще много полезных статей!
Премиум подписка - это доступ к эксклюзивным материалам, чтение канала без рекламы, возможность предлагать темы для статей и даже заказывать индивидуальные обзоры/исследования по своим запросам!Подробнее о том, какие преимущества вы получите с премиум подпиской, можно узнать здесь
Также подписывайтесь на нас в:
- Telegram: https://t.me/gergenshin
- Youtube: https://www.youtube.com/@gergenshin
- Яндекс Дзен: https://dzen.ru/gergen
- Официальный сайт: https://www-genshin.ru