Переменные в bash
Базовый синтаксис
Присваивание значения переменной:
Для получения значения переменной в bash нужно объявить знак доллара ($) и имя переменной. Такой вариант получения переменной удобен в работе со строками, а bash ориентирован именно на это, поэтому в нем используется именно такой подход.
Наглядно:
Юзай двойные кавычки
При использовании одинарных кавычек все символы интерпретируются в bash буквально и → никакой замены (например, ссылки переменной его значением) не будет. Поэтому нужно использовать двойные кавычки.
Пробелы не нужны
В операции присваивания пробелы вокруг ”=” не допускаются, ибо синтаксически вся конструкция присваивания должна быть одним “словом”.
В строках, где сложно определить, где заканчивается имя переменной, лучше использовать полный синтаксис - фигурные скобки вокруг имени переменной:
${FILE}
.
Подстановки/правки для возвращаемых значений переменной
Длина значения переменной
Фигурные скобки используются во многих синтаксических конструкциях, например, решетка (#) перед именем переменной ${#FILE}
возвращает длину значения (в символах). Наглядно:
Таким же образом работают и остальные синтаксические конструкции. Можно задать правила подстановки/правки, которые будут влиять на возвращаемое значение, но не на само значение переменной (есть исключение: Изменение значения).
Следующие несколько секций об этих правилах.
Short вариант команды basename
или удаление пути/префикса
Как ты знаешь скрипт можно вызывать разными способами, юзая:
./scriptname
из current dir- полный путь
/home/autistic/scripts/scriptname
вызов скрипта из директорий в PATH считается использованием абсолютного пути - относительный путь.
$0
будет хранить путь, который и использовался для вызова скрипта. А для идентификации скрипта, к примеру, в сообщении о порядке его использования (usage message) достаточно базового имени (тот же basename) без пути к нему:
Это пример удаления символов в начале/слева (префикса) строки. То есть, чтобы удалить префикс, нужно добавить в конструкцию ${VAR} решетку (#) и шаблон для удаления префикса.
${VAR#abc}
удалит символы abc, если c них начинается значение $VAR
${VAR#*abc}
удалит всё до символов abc ВКЛЮЧИТЕЛЬНО, кратчайшее совпадение (#)
${VAR##*abc}
тоже самое, но выбирается самое длинное совпадение ()
Наглядно:
Удаление пути к файлу:
Short вариант команды dirname или удаление суффикса
Подобно #, удаляющему префикс, знак % удаляет суффикс (символы справа).
И так же, двойной знак %% (вместе с *) удаляет всё после самого длинного совпадения.
Наглядно:
Эти выражения не полностью эквивалентны команде dirname: применительно к /file последнее выражение вернет пустую строку, а dirname - / (косую черту).
Но если нужна абсолютная схожесть с dirname в этих случаях, можно просто добавить слэш к выражению -${0%/*}/
- и результат будет заканчиваться слэшем.
"Запоминалка" для символов
Чтобы проще запомнить, что
#
удаляет префикс, а%
- суффикс, в книге предлагается аналогия с клавишами, где символ#
(Shift+3) находится слева от%
(Shift+5).
Модификаторы для преобразования в верхний/нижний регистры
С помощью ^
или ^^
можно преобразовать первый или все символы в верхний регистр, а с помощью ,
или ,,
- в нижний регистр.
Наглядно:
Info
А можно сразу объявить переменные в верхнем/нижнем регистрах:
Значения этих переменных будут всегда преобразовываться в указанный в параметрах declare регистр.
Модификатор замены / (слэш)
Выполняет люблю замену в любом месте строки (как в sed, например).
Нужно указать после / или // (для замены первого или всех совпадений, соответственно) искомый шаблон и через еще один слэш - строку замены.
НЕ ТРЕБУЕТСЯ завершающий слэш.
Наглядно:
Модификатор извлечения подстроки (substring)
Нужно добавить : (двоеточие) после имени переменной, указать порядковый номер символа (отсчет идет от 0) (начало подстроки), поставить еще одно : (двоеточие) и указать длину извлекаемой подстроки.
Наглядно:
Условные подстановки
Есть и условные подстановки, выполняющиеся при определенных условиях. Их особенность - : (двоеточие), после которого идет другой спец. символ: - (минус), + (плюс)
или = (знак равенства). Они проверяют, была ли создана переменная и имеет ли она значение. Несозданной (неустановленной) считается переменная, которой еще не было присвоено значение или которая была удалена с помощью команды unset. Позиционный параметр ($1, $2, …) считается несозданным, если пользователь не передал такой параметр.
Если из этих условных подстановок убрать двоеточие → они выполнятся, если переменная не создана; для созданных переменных вернутся их значения (даже если это пустая строка).
Дефолтные значения переменных
Один из частых применений условных подстановок - указаний дефолтных значений переменным, например, в скриптах с одним optional параметром. При использовании такой подстановки если параметр не был указан при вызове скрипта - присвоится указанное дефолтное значение.
Наглядно:
Выражение выше присвоит переменной LEN значение $1, либо 5, если последний не был указан.
Идиома соединения
Условная подстановка со знаком + проверяет, присвоено ли переменной какое-то значение (непустое) → если присвоено, возвращает указанное значение.
Встает вопрос: зачем возвращать какое-то другое значение, если переменная и так имеет свое??
С помощью такой подстановки можно создать, например, список значений, разделенных запятыми, без использования if для недопущения лишних запятых в начале/конце списка.
Идиома соединения наглядно (на примере создания списка значений с запятыми):
Изменение значения
Это то самое исключение, которое может менять значение переменной, в отличие от других подстановок. Это выражение ${VAR:=value}
, которая действует так же, как и ${VAR:-value}
, но ПРИСВОИТ переменной указанное значение и вернет это значение, если переменная не была еще создана или имела пустое значение (в то время, как ${VAR:-value}
просто возвращает указанное значение, не присваивая его).
Об этом исключении написал просто справедливости ради 🤓👆, ибо на деле используют эту идиому редко, потому что она не работает с позиционными параметрами ($1, $2, …).
Переменная $RANDOM
Из man bash
:
При каждом обращении к этой переменной генерируется случайное число от 0 до 32767. Присвоение значения этой переменной запускает генератор случайных чисел.
Естественно, такого диапазона чисел мало для написания всяких криптографических функций, но для добавления шума в слишком предсказуемые операции или моделирования игрового кубика сойдет.
Наглядно на примере выбора случайного элемента из списка:
Можно еще такой код встретить:
В источнике не рекомендуют этим кодом пользоваться (еще и без trap), ибо такой способ чреват состоянием гонки. Вообще для этого существует команда mktemp и на этом вопрос можно закрыть.
$RANDOM
недоступна вdash
В некоторых дистрибутивах ссылка /bin/sh указывает на dash, где не работает переменная $RANDOM. Актуальные версии Debian/Ubuntu используют dash, ибо он позволяет быстрее загружаться за счет меньшего объема и скорости по сравнению с bash.
Пару слов о подстановке команд
Команды внутри
$( )
работают в подоболочке.
Две эквивалентные строки, где вторая работает быстрее за счет использования внутренних механизмов командной оболочки:
Первый вариант - по сути, cat abuse.
Вложенная подстановка команд
Использование “ при вложенной подстановке команд (да и при обычной подстановке 🤢) выглядит особенно уродливо и чревато ошибками из-за сложного синтаксиса.
Соус: Книга “Идиомы Bash” → Глава 4. Язык переменных