Как разобрать аргументы командной строки в Bash?
У меня есть скрипт, который вызывается следующими командами:
./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
или вот так:
./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile
Как правильно разобрать входные параметры, чтобы в обоих случаях (или в любом их сочетании) переменные $v
, $f
и $d
были установлены в значение true
, а переменная $outFile
равнялась /fizz/someOtherFile
?
5 ответ(ов)
Этот скрипт deploy.sh
написан на Bash и позволяет пользователю указать параметры для деплоя. Ниже приведен перевод кода и его объяснение.
Код:
#!/bin/bash
while [[ "$#" -gt 0 ]]; do
case $1 in
-t|--target) target="$2"; shift ;;
-u|--uglify) uglify=1 ;;
*) echo "Неизвестный параметр: $1"; exit 1 ;;
esac
shift
done
echo "Куда деплоить: $target"
echo "Производить минификацию: $uglify"
Описание:
- #!/bin/bash — указывает на то, что скрипт должен выполняться с помощью интерпретатора
bash
. - while [[ "$#" -gt 0 ]]; do — продолжает выполнение цикла, пока количество аргументов больше 0.
- case $1 in — используется для разбора переданных параметров:
- -t|--target — если указан параметр
-t
или--target
, то следующий аргумент (целевой окружение) сохраняется в переменнойtarget
, и происходит сдвиг аргументов (shift) на один. - -u|--uglify — если указан параметр
-u
или--uglify
, то устанавливается переменнаяuglify
в 1, что может означать, что минификация должна быть выполнена. - *) — если передан неизвестный параметр, выводится сообщение об ошибке и скрипт завершается с кодом ошибки 1.
- -t|--target — если указан параметр
- echo — после обработки параметров скрипт выводит на экран значения переменных
target
иuglify
.
Пример использования:
Для запуска скрипта можно использовать такие команды:
./deploy.sh -t dev -u
# Либо:
./deploy.sh --target dev --uglify
В этих примерах -t dev
или --target dev
указывает, что деплой должен быть выполнен в окружение dev
, а -u
или --uglify
указывают на необходимость минификации кода.
Этот фрагмент кода на Bash выполняет обработку аргументов командной строки и имеет несколько полезных особенностей. Вот разбор его функциональности:
- Он обрабатывает флаги
-n arg
и--name=arg
, что делает его гибким в выборе формата ввода. - Код позволяет добавлять аргументы в самом конце, что удобно для пользователя.
- В случае неправильно указанных аргументов, выводятся информативные ошибки, что упрощает отладку.
- Реализация совместима и не использует специфичные конструкции Bash (bashisms), что делает его более переносимым.
- Код читабелен и не требует поддержки состояния в цикле, что упрощает понимание логики.
Таким образом, этот код является хорошим примером обработки аргументов командной строки в Bash, который учитывает различные сценарии использования и обеспечивает ошибки в случае некорректного ввода.
Перевод на русский в стиле ответа на StackOverflow.com:
Я использовал предыдущие ответы как отправную точку для упорядочивания своего старого разбора параметров. После этого я выделил следующий шаблон кода. Он обрабатывает как длинные, так и короткие параметры, учитывает аргументы, разделенные знаком равенства или пробелом, а также несколько коротких параметров, сгруппированных вместе. Наконец, он вновь вставляет любые не параметрические аргументы в переменные $1, $2 и т.д.
#!/usr/bin/env bash
# ПРИМЕЧАНИЕ: Раскомментируйте, если ваш скрипт зависит от bash-специфик.
#if [ -z "$BASH_VERSION" ]; then bash $0 $@ ; exit $? ; fi
echo "До"
for i ; do echo - $i ; done
# Шаблон кода для разбора параметров командной строки, используя только переносимый shell код,
# обрабатывая как длинные, так и короткие параметры, обрабатывая данные параметров в формате '-f file'
# и '-f=file' и также захватывая не параметры для последующей вставки
# обратно в позиционные параметры shell.
while [ -n "$1" ]; do
# Копируем, чтобы иметь возможность изменить (нельзя изменять $1)
OPT="$1"
# Обнаружение завершения аргументов
if [ x"$OPT" = x"--" ]; then
shift
for OPT ; do
REMAINS="$REMAINS \"$OPT\""
done
break
fi
# Разбор текущего параметра
while [ x"$OPT" != x"-" ] ; do
case "$OPT" in
# Обработка параметров вида --flag=value
-c=* | --config=* )
CONFIGFILE="${OPT#*=}"
shift
;;
# Параметры вида --flag value
-c* | --config )
CONFIGFILE="$2"
shift
;;
-f* | --force )
FORCE=true
;;
-r* | --retry )
RETRY=true
;;
# Все неизвестные записываются для последующей обработки
* )
REMAINS="$REMAINS \"$OPT\""
break
;;
esac
# Проверяем на наличие нескольких коротких опций
# ПРИМЕЧАНИЕ: убедитесь, что вы обновили этот шаблон, чтобы он соответствовал допустимым опциям
NEXTOPT="${OPT#-[cfr]}" # пытаемся удалить отдельную короткую опцию
if [ x"$OPT" != x"$NEXTOPT" ] ; then
OPT="-$NEXTOPT" # несколько коротких опций, продолжаем
else
break # длинная форма, выходим из внутреннего цикла
fi
done
# Завершили с этим параметром. Переходим к следующему
shift
done
# Устанавливаем не параметры обратно в позиционные параметры ($1 $2 ..)
eval set -- $REMAINS
echo -e "После: \n configfile='$CONFIGFILE' \n force='$FORCE' \n retry='$RETRY' \n remains='$REMAINS'"
for i ; do echo - $i ; done
Если у вас есть дополнительные вопросы или нужны пояснения по коду, не стесняйтесь задавать их!
Этот пример демонстрирует, как использовать getopt
, eval
, HEREDOC
и shift
для обработки коротких и длинных параметров с и без обязательного значения, которое следует за ними. Также конструкция switch/case
лаконична и легка для понимания.
#!/usr/bin/env bash
# Функция использования
function usage()
{
cat << HEREDOC
Использование: $progname [--num NUM] [--time TIME_STR] [--verbose] [--dry-run]
необязательные аргументы:
-h, --help показать это сообщение и выйти
-n, --num NUM передать число
-t, --time TIME_STR передать строку времени
-v, --verbose увеличить уровень подробности скрипта
--dry-run выполнить пробный запуск, не изменяя файлы
HEREDOC
}
# Инициализация переменных
progname=$(basename $0)
verbose=0
dryrun=0
num_str=
time_str=
# Использование getopt и сохранение вывода в $OPTS
# Обратите внимание на использование -o для коротких параметров, --long для длинных
# и : для любого параметра, который принимает значение
OPTS=$(getopt -o "hn:t:v" --long "help,num:,time:,verbose,dry-run" -n "$progname" -- "$@")
if [ $? != 0 ] ; then echo "Ошибка в аргументах командной строки." >&2 ; usage; exit 1 ; fi
eval set -- "$OPTS"
while true; do
# раскомментируйте следующую строку, чтобы увидеть, как работает shift
# echo "\$1:\"$1\" \$2:\"$2\""
case "$1" in
-h | --help ) usage; exit; ;;
-n | --num ) num_str="$2"; shift 2 ;;
-t | --time ) time_str="$2"; shift 2 ;;
--dry-run ) dryrun=1; shift ;;
-v | --verbose ) verbose=$((verbose + 1)); shift ;;
-- ) shift; break ;;
* ) break ;;
esac
done
if (( $verbose > 0 )); then
# вывод всех переданных параметров
cat <<EOM
num=$num_str
time=$time_str
verbose=$verbose
dryrun=$dryrun
EOM
fi
# Остальная часть вашего скрипта ниже
Наиболее значимые строки этого скрипта:
OPTS=$(getopt -o "hn:t:v" --long "help,num:,time:,verbose,dry-run" -n "$progname" -- "$@")
if [ $? != 0 ] ; then echo "Ошибка в аргументах командной строки." >&2 ; exit 1 ; fi
eval set -- "$OPTS"
while true; do
case "$1" in
-h | --help ) usage; exit; ;;
-n | --num ) num_str="$2"; shift 2 ;;
-t | --time ) time_str="$2"; shift 2 ;;
--dry-run ) dryrun=1; shift ;;
-v | --verbose ) verbose=$((verbose + 1)); shift ;;
-- ) shift; break ;;
* ) break ;;
esac
done
Кратко, по делу, читаемо и обрабатывает почти все (на мой взгляд).
Надеюсь, это поможет кому-то.
Этот скрипт на Bash позволяет обрабатывать аргументы командной строки, используя как разделенные пробелами опции/значения, так и значения, определенные через знак равенства. Он поддерживает флаги и аргументы с заданными значениями, а также прост в использовании и не требует дополнительных библиотек, таких как getopt
или getopts
.
Пример использования:
./myscript --foo -b -o /fizz/file.txt
или
./myscript -f --bar -o=/fizz/file.txt
Оба варианта вызова скрипта дадут одинаковый результат.
Преимущества:
Поддерживает как формат
-arg=value
, так и-arg value
Работает с любым именем аргумента, используемым в Bash
- Это значит, что можно использовать как
-a
, так и-arg
,--arg
,-a-r-g
и т.д.
- Это значит, что можно использовать как
Чистый Bash. Нет необходимости изучать или использовать
getopt
илиgetopts
Недостатки:
Нельзя комбинировать аргументы
- Например, формат
-abc
не поддерживается: нужно использовать-a -b -c
- Например, формат
Таким образом, предоставленный код обеспечивает хорошую гибкость в обработке аргументов, позволяя разрабатывать удобные командные утилиты с простым синтаксисом.
Как запросить ввод Yes/No/Cancel в скрипте оболочки Linux?
Как объявить и использовать логические переменные в shell-скрипте?
Как изменить цвет вывода echo в Linux
Как работает "cat << EOF" в bash?
Передача параметров в функцию Bash