getopts в Bash: параметр пропущен или его значение начинается с минуса
У небольшого экспортёра появляется параметр -n: сколько записей показать. Затем кто-то вызывает его без числа, а другой передаёт файл с именем -report.csv. Если разбирать аргументы простым shift в нескольких местах, легко перепутать значение опции с именем файла.
Встроенный getopts обрабатывает короткие опции и хранит позицию в OPTIND. Двоеточие после буквы в строке опций означает обязательный аргумент. Необязательные аргументы опций этот builtin не предоставляет: для понятного интерфейса лучше отдельная опция-флаг или явное значение.
Определим один устойчивый интерфейс
Скрипт принимает -n NUMBER и ровно одно имя файла. По умолчанию число равно десяти. Два минуса завершают опции: всё после них считается позиционными аргументами. Сам пример ничего не читает и не записывает, а печатает разобранный запрос.
#!/usr/bin/env bash
limit=10
OPTIND=1
while getopts ':n:h' option; do
case "$option" in
n) limit=$OPTARG ;;
h) printf 'Usage: %s [-n NUMBER] -- FILE
' "$0"; exit 0 ;;
:) printf 'Missing value for -%s
' "$OPTARG" >&2; exit 2 ;;
\?) printf 'Unknown option: -%s
' "$OPTARG" >&2; exit 2 ;;
esac
done
shift "$((OPTIND - 1))"
if [[ ! $limit =~ ^[1-9][0-9]{0,3}$ || $# -ne 1 ]]; then
printf 'Expected limit 1..9999 and one file
' >&2
exit 2
fi
printf 'limit=%s file=%s
' "$limit" "$1"
Сохраните код в options.sh. Вызов bash options.sh -n 25 -- -report.csv даст limit=25 file=-report.csv. Кавычки при вызове сохраняют имя с пробелом одним аргументом. getopts уже работает с готовыми аргументами и не может восстановить границы, потерянные оболочкой до запуска.
Начальное двоеточие включает тихий режим ошибок: при отсутствии значения ветка получает символ :, при неизвестной опции — ?. Поэтому сообщения принадлежат нашему интерфейсу и идут в stderr. После цикла shift удаляет только обработанную часть, оставляя исходные позиционные аргументы.
Минус не доказывает отсутствие значения
Вызов -n -3 передаст строку -3 как значение n. Для опции с обязательным аргументом это ожидаемо. Уже проверка диапазона решает, допустимо ли отрицательное число. Нельзя определять пропуск значения только по первому символу: для других параметров путь или шаблон действительно может начинаться с минуса.
В примере диапазон ограничен длиной и регулярным выражением. Значения 0, 10000, 08 и выражения вроде 1+1 отклоняются. Это отдельный договор команды; getopts отвечает за структуру, а смысл аргумента проверяет приложение. Файл с именем -x передавайте после --, иначе он выглядит неизвестной опцией.
Проверим не только удачный вызов
Пустой вызов, -n без значения, неизвестный -z и два имени файла должны дать код 2. Вызов -h должен успешно показать инструкцию. Для повторного разбора внутри функции обнуляйте позицию через local OPTIND=1: иначе второй вызов может начать чтение с прежнего места.
Этот каркас легко расширить флагом подробного журнала. Но длинные опции вроде --limit не стоит притворно поддерживать одной заменой строки getopts. Если они нужны пользователям, выберите отдельный разбор и добавьте явные проверки тех же граничных случаев.
В курсе Bash Linux + Git есть аргументы, условия, функции и практические скрипты. Эти навыки позволяют довести полезную команду до инструмента, который коллега запустит без догадок. Откройте программу и отработайте интерфейс скрипта на задачах.
Продолжить на практике
- Bash Linux + Git: от новичка до уверенного пользователя ↗
Освоим два важнейших инструмента разработчика: применение bash-скриптов в практических задачах и git в его самых разных проявлениях.
