Справочники
Шпаргалка bash
Подстановки параметров, массивы, условия и ловушки — с разбором выражения и наглядной разницей «$@» и «$*».
Живой разбор
Проверить подстановку параметра
Поддержаны :- := :? :+ # ## % %% / // : ^ ^^ , ,, и ${#имя}
Результат
error.log
Убран длиннейший префикс, подходящий под «*/».
Почему скрипты ломаются на пробелах
«$@» против «$*»
Разделяйте точкой с запятой — так видно, где кончается аргумент с пробелом.
| Форма | Что получит команда | Слов |
|---|---|---|
| "$@" | одиндва словатриКаждый аргумент остаётся отдельным словом целиком. Единственная безопасная форма. | 3 |
| "$*" | один два слова триОдно слово: аргументы склеены первым символом IFS (пробел). | 1 |
| $@ | одиндвасловатриКавычек нет — каждое значение дополнительно рвётся по пробелам. | 4 |
| $* | одиндвасловатриБез кавычек ведёт себя так же, как $@: склейка теряется при разбиении слов. | 4 |
Показано 77 из 77 строк.
Подстановка параметров
Двоеточие в форме означает «пустая строка считается за отсутствие». Без двоеточия пустая строка — полноценное значение.
${name:-по умолчанию}
Значение, а если пусто или не задано — подставить текст. Саму переменную не меняет.
${name-по умолчанию}
То же, но пустая строка считается заданным значением.
${name:=по умолчанию}
Подставить и заодно присвоить переменной.
${name:?нужен name}
Прервать скрипт с этим сообщением, если переменная пуста.
${name:+--flag}
Подставить текст только если переменная непуста — удобно для необязательных флагов.
${#name}
Длина значения в символах.
${name#*/}
Убрать кратчайший префикс по шаблону.
${name##*/}
Убрать длиннейший префикс — то же, что basename.
${name%/*}
Убрать кратчайший суффикс — то же, что dirname.
${name%%.*}
Убрать длиннейший суффикс — имя файла без всех расширений.
${name/старое/новое}
Заменить первое вхождение.
${name//старое/новое}
Заменить все вхождения.
${name/#пре/новое}
Заменить только в начале; /% — только в конце.
${name:7:3}
Подстрока: смещение 7, длина 3. Отрицательное смещение — через пробел: ${name: -3}.
${name^^}
ВЕРХНИЙ регистр целиком; ^ — только первая буква.
${name,,}
нижний регистр целиком; , — только первая буква.
${!prefix*}
Имена всех переменных, начинающихся с prefix.
${!name}
Косвенная ссылка: значение переменной, чьё имя лежит в name.
Аргументы и специальные переменные
"$@" в кавычках — единственная форма, которая переживает пробелы в аргументах. Всё остальное рано или поздно ломается на пути «Мои документы».
"$@"
Все аргументы, каждый — отдельным словом. Это правильный вариант.
"$*"
Все аргументы одной строкой через первый символ IFS (обычно пробел).
$@ без кавычек
Каждый аргумент дополнительно рвётся по пробелам — почти всегда ошибка.
$#
Сколько аргументов передано.
$0
Имя самого скрипта.
$1 … $9, ${10}
Позиционные аргументы; с десятого — обязательно в фигурных скобках.
$?
Код возврата предыдущей команды. 0 — успех.
$$
PID текущего скрипта; $! — PID последнего фонового процесса.
shift 2
Сдвинуть аргументы: $3 становится $1.
set -- a b c
Переписать список позиционных аргументов.
local -n ref=$1
Ссылка на переменную по имени внутри функции (bash 4.3+).
Массивы и ассоциативные массивы
arr=(один два "три с пробелом")
Объявление обычного массива.
"${arr[@]}"
Все элементы, каждый отдельным словом. В кавычках — обязательно.
${#arr[@]}
Число элементов; ${#arr[0]} — длина первого.
${arr[-1]}
Последний элемент (bash 4.3+).
"${arr[@]:1:2}"
Срез: два элемента начиная со второго.
arr+=(ещё)
Добавить в конец.
for x in "${arr[@]}"; do echo "$x"; done
Правильный перебор массива.
declare -A map
Ассоциативный массив; без объявления bash сделает обычный и молча испортит ключи.
map[ключ]=значение
Запись; ${map[ключ]} — чтение.
"${!map[@]}"
Все ключи; "${map[@]}" — все значения.
mapfile -t lines < file.txt
Файл в массив строк без завершающих переводов строки.
IFS=, read -ra parts <<< "$csv"
Разбить строку по запятой в массив.
Условия и сравнения
[[ ]] — встроенная конструкция bash: не рвёт слова, понимает && и =~. [ ] — внешняя команда, там каждую переменную надо брать в кавычки.
[[ -z "$s" ]]
Строка пуста; -n — непуста.
[[ "$a" == "$b" ]]
Строки равны; != — не равны.
[[ "$s" == п* ]]
Справа шаблон, а не строка: без кавычек это сравнение с образцом.
[[ "$s" =~ ^[0-9]+$ ]]
Регулярное выражение; группы попадают в ${BASH_REMATCH[1]}.
(( a > b ))
Арифметическое сравнение. Внутри знак $ перед именами не нужен.
[[ "$a" -eq "$b" ]]
Числовое равенство: -eq -ne -lt -le -gt -ge.
[[ -f "$f" ]]
Обычный файл существует; -d — каталог, -e — что угодно, -L — ссылка.
[[ -s "$f" ]]
Файл существует и непустой.
[[ -r "$f" && -w "$f" ]]
Доступен на чтение и запись.
[[ "$f1" -nt "$f2" ]]
Первый файл новее второго; -ot — старее.
if command -v jq >/dev/null; then …; fi
Проверить, что программа установлена.
case "$1" in start) … ;; stop) … ;; *) … ;; esac
Разбор по вариантам вместо лестницы if.
Надёжный скрипт: ловушки и защита
set -Eeuo pipefail
Падать на ошибке, на необъявленной переменной и на ошибке внутри конвейера. Первая строка любого скрипта.
IFS=$'\n\t'
Убрать пробел из разделителей — меньше сюрпризов при разбиении слов.
trap cleanup EXIT
Выполнить функцию при любом выходе, в том числе по ошибке.
trap 'echo "строка $LINENO"' ERR
Показать, где именно упало (нужен set -E).
tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT
Временный каталог, который уберётся сам.
command || true
Разрешить одной команде упасть, не роняя скрипт с set -e.
if ! out=$(cmd 2>&1); then echo "$out" >&2; exit 1; fi
Поймать вывод и код возврата разом.
exec 200>/var/lock/my.lock; flock -n 200 || exit 1
Не дать скрипту запуститься дважды.
readonly CONFIG=/etc/app.conf
Константа: переприсваивание станет ошибкой.
printf '%s\n' "$var"
Безопасная печать: echo калечит строки, начинающиеся с - или содержащие \n.
"${BASH_SOURCE[0]}"
Путь к самому скрипту даже при source; $0 в этом случае врёт.
cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1
Перейти в каталог скрипта, что бы ни было текущим.
Потоки, конвейеры, подстановки
cmd > out.txt 2>&1
И вывод, и ошибки в файл. Порядок важен: 2>&1 > file так не работает.
cmd &> out.txt
То же короче (bash).
cmd 2>/dev/null
Выбросить только ошибки.
cmd >> out.txt
Дописать в конец, а не перезаписать.
out=$(cmd)
Подстановка команды. Обратные кавычки — устаревшая форма, не вкладываются.
diff <(cmd1) <(cmd2)
Подстановка процесса: вывод команды как файл.
cat <<'EOF' > file
Heredoc. Кавычки вокруг EOF отключают подстановку переменных внутри.
cat <<-EOF
Дефис позволяет отбивать тело табуляциями.
read -r line <<< "$string"
Herestring: строка на вход команде.
while IFS= read -r line; do echo "$line"; done < file
Правильное чтение файла по строкам: IFS= сохраняет отступы, -r не ест \.
cmd | tee -a log.txt
И на экран, и в файл.
set -o pipefail
Код возврата конвейера — от первой упавшей команды, а не от последней.