26

Как разобрать аргументы командной строки в Bash?

28

У меня есть скрипт, который вызывается следующими командами:

./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 ответ(ов)

4

Этот скрипт 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.
  • echo — после обработки параметров скрипт выводит на экран значения переменных target и uglify.

Пример использования:

Для запуска скрипта можно использовать такие команды:

./deploy.sh -t dev -u

# Либо:

./deploy.sh --target dev --uglify

В этих примерах -t dev или --target dev указывает, что деплой должен быть выполнен в окружение dev, а -u или --uglify указывают на необходимость минификации кода.

1

Этот фрагмент кода на Bash выполняет обработку аргументов командной строки и имеет несколько полезных особенностей. Вот разбор его функциональности:

  • Он обрабатывает флаги -n arg и --name=arg, что делает его гибким в выборе формата ввода.
  • Код позволяет добавлять аргументы в самом конце, что удобно для пользователя.
  • В случае неправильно указанных аргументов, выводятся информативные ошибки, что упрощает отладку.
  • Реализация совместима и не использует специфичные конструкции Bash (bashisms), что делает его более переносимым.
  • Код читабелен и не требует поддержки состояния в цикле, что упрощает понимание логики.

Таким образом, этот код является хорошим примером обработки аргументов командной строки в Bash, который учитывает различные сценарии использования и обеспечивает ошибки в случае некорректного ввода.

0

Перевод на русский в стиле ответа на 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

Если у вас есть дополнительные вопросы или нужны пояснения по коду, не стесняйтесь задавать их!

0

Этот пример демонстрирует, как использовать 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

Кратко, по делу, читаемо и обрабатывает почти все (на мой взгляд).

Надеюсь, это поможет кому-то.

0

Этот скрипт на 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

Таким образом, предоставленный код обеспечивает хорошую гибкость в обработке аргументов, позволяя разрабатывать удобные командные утилиты с простым синтаксисом.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь