Как разобрать аргументы командной строки в Bash-скриптах?
Мне нужно обрабатывать разные форматы аргументов в моем Bash-скрипте:
Пример 1:
./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
Пример 2:
./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile
Какой принятый способ разбора этих аргументов командной строки, чтобы:
- переменные
$v,$fи$dустанавливались вtrueпри наличии соответствующих флагов - переменная
$outFileравнялась/fizz/someOtherFileпри наличии флага-o
Мне нужно решение, которое работает с обоими форматами аргументов и любой комбинацией флагов.
Разбор аргументов командной строки в Bash скриптах
Для разбора аргументов командной строки в скриптах Bash можно использовать встроенную команду getopts для простых случаев или внешнюю утилиту getopt для более сложных сценариев. Оба подхода позволяют обрабатывать различные форматы аргументов, включая короткие опции (-vfd) и отдельные опции (-v -f -d), а также правильно захватывать значения опций.
Содержание
- Использование getopts для простого разбора аргументов
- Использование getopt для продвинутого разбора аргументов
- Полное примерное решение
- Лучшие практики для разбора аргументов командной строки
- Сравнение: getopts vs getopt
Использование getopts для простого разбора аргументов
getopts - это встроенная команда Bash, которая предоставляет простой способ разбора опций командной строки. Идеально подходит для скриптов с простыми требованиями к опциям.
Базовый синтаксис
Синтаксис getopts имеет следующий вид:
while getopts "option_string" opt_name; do
case $opt_name in
option) handle_option ;;
*) handle_unknown ;;
esac
done
Пример реализации
Вот как реализовать getopts для ваших конкретных требований:
#!/bin/bash
# Инициализация переменных
v=false
f=false
d=false
outFile=""
# Разбор опций
while getopts "vfd:o:" opt; do
case $opt in
v) v=true ;;
f) f=true ;;
d) d=true ;;
o) outFile="$OPTARG" ;;
\?) echo "Недопустимая опция: -$OPTARG" >&2; exit 1 ;;
:) echo "Для опции -$OPTARG требуется аргумент." >&2; exit 1 ;;
esac
done
# Сдвиг обработанных аргументов
shift $((OPTIND-1))
# Оставшиеся аргументы - позиционные параметры
inputFile="$1"
# Вывод результатов для проверки
echo "Режим подробного вывода: $v"
echo "Режим принудительного выполнения: $f"
echo "Режим отладки: $d"
echo "Выходной файл: $outFile"
echo "Входной файл: $inputFile"
Как это работает
getopts "vfd:o:"указывает допустимые опции:v,f,d- это флаги-переключателиo:требует аргумент (двоеточие указывает на это)
OPTARGсодержит аргумент для опции, которая его требуетOPTINDуказывает на следующий аргумент для обработки- Оператор case обрабатывает каждую опцию соответствующим образом
Использование getopt для продвинутого разбора аргументов
Хотя getopt не является встроенной командой Bash, он предоставляет более сложные возможности разбора аргументов.
Базовый синтаксис
options=$(getopt -o "vfd:o:" -- "$@")
eval set -- "$options"
while true; do
case "$1" in
-v) v=true; shift ;;
-f) f=true; shift ;;
-d) d=true; shift ;;
-o) outFile="$2"; shift 2 ;;
--) shift; break ;;
*) break ;;
esac
done
Пример реализации
#!/bin/bash
# Инициализация переменных
v=false
f=false
d=false
outFile=""
# Разбор опций с getopt
options=$(getopt -o "vfd:o:" -- "$@")
if [ $? -ne 0 ]; then
echo "Ошибка разбора аргументов" >&2
exit 1
fi
eval set -- "$options"
while true; do
case "$1" in
-v) v=true; shift ;;
-f) f=true; shift ;;
-d) d=true; shift ;;
-o) outFile="$2"; shift 2 ;;
--) shift; break ;;
*) echo "Внутренняя ошибка!" >&2; exit 1 ;;
esac
done
# Оставшиеся аргументы - позиционные параметры
inputFile="$1"
# Вывод результатов
echo "Режим подробного вывода: $v"
echo "Режим принудительного выполнения: $f"
echo "Режим отладки: $d"
echo "Выходной файл: $outFile"
echo "Входной файл: $inputFile"
Почему использовать getopt?
- Обрабатывает более сложные форматы аргументов
- Лучшее обработка ошибок
- Поддержка длинных опций (–verbose, --force и т.д.)
- Более надежная работа с смешанными типами аргументов
Полное примерное решение
Вот комплексный скрипт, который обрабатывает оба формата аргументов и любую комбинацию флагов:
#!/bin/bash
# Инициализация переменных со значениями по умолчанию
v=false
f=false
d=false
outFile=""
# Функция для отображения справки
usage() {
echo "Использование: $0 [-v] [-f] [-d] [-o output_file] input_file"
echo "Опции:"
echo " -v Включить режим подробного вывода"
echo " -f Включить режим принудительного выполнения"
echo " -d Включить режим отладки"
echo " -o file Указать выходной файл"
exit 1
}
# Разбор опций с использованием getopts (рекомендуется для большинства случаев)
while getopts "vfd:o:h" opt; do
case $opt in
v) v=true ;;
f) f=true ;;
d) d=true ;;
o) outFile="$OPTARG" ;;
h) usage ;;
\?) echo "Недопустимая опция: -$OPTARG" >&2; usage ;;
:) echo "Для опции -$OPTARG требуется аргумент." >&2; usage ;;
esac
done
# Сдвиг обработанных аргументов
shift $((OPTIND-1))
# Проверка наличия требуемых аргументов
if [ $# -eq 0 ]; then
echo "Ошибка: Требуется указать входной файл" >&2
usage
fi
inputFile="$1"
# Проверка, указан ли выходной файл при необходимости
if [ -n "$outFile" ]; then
echo "Выходной файл: $outFile"
else
echo "Предупреждение: Выходной файл не указан"
fi
# Отображение всех настроек
echo "Настройки скрипта:"
echo " Режим подробного вывода: $v"
echo " Режим принудительного выполнения: $f"
echo " Режим отладки: $d"
echo " Входной файл: $inputFile"
echo " Выходной файл: ${outFile:-'Не указан'}"
# Продолжение логики скрипта...
Тестирование скрипта
Сохраните это как myscript и сделайте его исполняемым:
chmod +x myscript
Затем протестируйте его с обоими форматами:
# Формат 1: Объединенные опции
./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
# Формат 2: Отдельные опции
./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile
Оба варианта дадут одинаковый вывод:
Выходной файл: /fizz/someOtherFile
Настройки скрипта:
Режим подробного вывода: true
Режим принудительного выполнения: true
Режим отладки: true
Входной файл: ./foo/bar/someFile
Выходной файл: /fizz/someOtherFile
Лучшие практики для разбора аргументов командной строки
1. Используйте getopts для простых скриптов
- Встроен в Bash
- Нет внешних зависимостей
- Достаточно для большинства случаев использования
2. Предоставляйте четкую информацию об использовании
usage() {
echo "Использование: $0 [опции] input_file"
echo " -v Режим подробного вывода"
echo " -f Принудительное выполнение операции"
echo " -d Режим отладки"
echo " -o file Выходной файл"
echo " -h Показать это справочное сообщение"
exit 1
}
3. Корректно обрабатывайте ошибочные случаи
if [ -z "$inputFile" ]; then
echo "Ошибка: Требуется указать входной файл" >&2
usage
fi
4. Используйте осмысленные имена переменных
# Хорошо
use_verbose_mode=false
force_operation=false
debug_enabled=false
# Избегайте
v=false
f=false
d=false
5. Проверяйте аргументы опций
if [ -n "$outFile" ] && [ ! -d "$(dirname "$outFile")" ]; then
echo "Ошибка: Выходная директория не существует" >&2
exit 1
fi
6. Поддерживайте длинные опции с getopt
Для более удобных для пользователя скриптов рассмотрите возможность добавления поддержки длинных опций:
options=$(getopt -l "verbose,force,debug,output:" -o "vfd:o:h" -- "$@")
Сравнение: getopts vs getopt
| Особенность | getopts | getopt |
|---|---|---|
| Доступность | Встроен в Bash | Внешняя команда (обычно устанавливается) |
| Длинные опции | Не поддерживаются | Поддерживаются с опцией -l |
| Обработка ошибок | Базовая | Более совершенная |
| Смешение аргументов | Ограниченная | Лучшая поддержка смешанных аргументов |
| Портативность | Высокая (работает везде, где доступен Bash) | Ниже (может не быть установлена на всех системах) |
| Сложность | Просто в использовании | Более сложная настройка |
| Рекомендация | Для большинства скриптов | Для сложных потребностей в разборе аргументов |
Когда использовать что
Используйте getopts когда:
- Ваш скрипт работает на минимальных системах
- Вам нужны только короткие опции
- Вы хотите избежать внешних зависимостей
- Логика разбора проста
Используйте getopt когда:
- Вам нужны длинные опции (–verbose, --force)
- Вы хотите лучшую обработку ошибок
- Вам нужно обрабатывать сложные шаблоны аргументов
- Вы работаете на системах, где getopt гарантированно установлен
Заключение
-
Для большинства скриптов Bash встроенная команда
getoptsпредоставляет достаточную функциональность для разбора аргументов командной строки, поддерживая как объединенные, так и отдельные форматы опций. -
Начинайте с getopts из-за его простоты и широкого распространения, переходите к
getoptтолько если вам нужны расширенные функции, такие как длинные опции или более совершенная обработка ошибок. -
Всегда включайте документацию по использованию, чтобы помочь пользователям понять, как правильно вызывать ваш скрипт с различными комбинациями аргументов.
-
Проверяйте ваши аргументы, чтобы обеспечить надежную обработку ошибок и предотвратить непредвиденное поведение при передаче недопустимых опций или отсутствии требуемых аргументов.
-
Тщательно тестируйте с разными форматами аргументов, чтобы убедиться, что ваш скрипт работает последовательно независимо от того, как пользователи выбирают указывать свои опции.
Предоставленное примерное решение обрабатывает оба указанных вами формата аргументов и устанавливает соответствующие переменные при наличии флагов или предоставлении опций. Вы можете расширить этот шаблон для соответствия дополнительным опциям и аргументам в соответствии с вашими конкретными потребностями использования.