Bash скрипт: аргументы, getopts и set -euo pipefail
Аргументы скрипта доступны в переменных $1, $2 и далее, их количество в $#, а все сразу в "$@". Для ключей вроде -v и -n 5 используют встроенную команду getopts. В начале надёжного скрипта пишут set -euo pipefail, чтобы он останавливался при ошибках.
Позиционные параметры
#!/usr/bin/env bash
echo "Скрипт: $0"
echo "Первый аргумент: $1"
echo "Второй аргумент: $2"
echo "Всего аргументов: $#"
echo "Все аргументы: $@"Запуск ./args.sh один два выведет один, два и 2. Переменная $0 хранит имя запущенного скрипта.
Переменная | Значение |
|---|---|
| Имя скрипта |
| Аргументы по номерам; после девятого используйте |
| Количество аргументов |
| Все аргументы, каждый отдельным словом |
| Код выхода последней команды |
Всегда пишите "$@" в кавычках: тогда аргументы с пробелами не распадутся на части.
Значения по умолчанию и проверка
#!/usr/bin/env bash
name="${1:-мир}" # если аргумента нет, подставить «мир»
if [ $# -lt 1 ]; then
echo "Использование: $0 имя" >&2
exit 1
fi
echo "Привет, $name"Запись ${1:?сообщение} останавливает скрипт с ошибкой, если аргумента нет.
Ключи через getopts
#!/usr/bin/env bash
verbose=0
count=1
while getopts "vn:h" opt; do
case "$opt" in
v) verbose=1 ;;
n) count="$OPTARG" ;;
h) echo "Использование: $0 [-v] [-n число] файл"; exit 0 ;;
*) echo "Неизвестный ключ" >&2; exit 2 ;;
esac
done
shift $((OPTIND - 1)) # убрать разобранные ключи, остаются позиционные
file="${1:?Не указан файл}"
echo "verbose=$verbose count=$count file=$file"В строке "vn:h" двоеточие после буквы означает, что у ключа есть значение: n: принимает -n 5, оно попадает в $OPTARG. Команда getopts понимает только короткие ключи, для длинных вроде --verbose используйте case по $1 и shift.
Строгий режим
#!/usr/bin/env bash
set -euo pipefailФлаг | Что делает |
|---|---|
| Завершить скрипт, если команда вернула ошибку |
| Считать ошибкой обращение к неопределённой переменной |
| Конвейер падает, если ошибка в любой его команде, а не только в последней |
Функции и коды выхода
#!/usr/bin/env bash
check_file() {
[ -f "$1" ] || { echo "Нет файла: $1" >&2; return 1; }
echo "Файл найден: $1"
}
check_file "$1" || exit 1Запрос данных у пользователя
read -r -p "Продолжить? [y/N] " answer
[ "$answer" = "y" ] || exit 0Сделать скрипт исполняемым
chmod +x script.sh
./script.sh -v -n 3 data.txtЧастые вопросы
Чем $@ отличается от $*?
Без кавычек они одинаковы. В кавычках "$@" сохраняет границы аргументов, а "$*" склеивает всё в одну строку.
Как обработать аргументы по очереди в цикле?
for arg in "$@"; do echo "$arg"; done или циклом с shift: while [ $# -gt 0 ]; do ...; shift; done.
Зачем в начале скрипта строка с #!?
Она сообщает системе, чем выполнять файл. Запись #!/usr/bin/env bash находит Bash в PATH, она переносимее, чем #!/bin/bash.