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 есть аргументы, условия, функции и практические скрипты. Эти навыки позволяют довести полезную команду до инструмента, который коллега запустит без догадок. Откройте программу и отработайте интерфейс скрипта на задачах.

Продолжить на практике