Кроссплатформенный getopt для скрипта оболочки - PullRequest
11 голосов
/ 27 апреля 2010

Я только что обнаружил, что getopt не является кроссплатформенным (в частности, для FreeBSD и Linux). Как лучше обойти эту проблему?

Ответы [ 4 ]

29 голосов
/ 29 ноября 2010

Существуют две версии команды getopt: исходная версия и расширенная версия GNU. Улучшенная версия GNU обратно совместима с оригинальной версией, поэтому, если вы используете только функции оригинальной версии, она будет работать с обоими.

Определить, какая версия getopt доступна

Вы можете определить, какая версия доступна, и использовать расширенные функции, если доступна расширенная версия GNU, и ограничиться исходными функциями, если расширенная версия GNU недоступна. В расширенной версии есть опция -T для проверки, какая версия доступна.

getopt -T > /dev/null
if [ $? -eq 4 ]; then
    # GNU enhanced getopt is available
    set -- `getopt --long help,output:,version --options ho:v -- "$@"`
else
    # Original getopt is available
    set -- `getopt ho:v "$@"`
fi

Попробуйте вместо этого использовать встроенную команду оболочки getopts (с "s"), потому что она более переносима. Однако getopts не поддерживает длинные опции (например, --help).

Если вам нравятся длинные опции, используйте getopt и используйте вышеуказанный тест, чтобы увидеть, доступна ли расширенная версия GNU getopt или нет. Если расширенная версия недоступна, сценарий может постепенно перейти на исходную версию getopt (без поддержки длинных имен параметров и без пробелов) или с использованием getopts (без поддержки длинных имен параметров) .

Правильное использование расширенного getopt в GNU

Получить расширенную версию GNU для правильной обработки аргументов с пробелами довольно сложно. Вот как это делается:

ARGS=`getopt --long help,output:,verbose --options ho:v -- "$@"`
if [ $? -ne 0 ]; then
  echo "Usage error (use -h for help)" >&2
  exit 2
fi
eval set -- $ARGS

# Parameters are now sorted: options appear first, followed by --, then arguments
# e.g. entering: "foo bar" -o abc baz -v
#      produces: -o 'abc' -v -- 'foo bar' 'baz'

Секрет в том, чтобы использовать "$@", где двойные кавычки очень важны (в строке 1), и eval команду set (в строке 6).

Таким образом, ошибки, вызванные getopt, могут быть обнаружены и обработаны, вызов getopt выполняется отдельно от eval с двумя связанными переменной ARGS.

Полный рабочий пример

PROG=`basename $0`

getopt -T > /dev/null
if [ $? -eq 4 ]; then
  # GNU enhanced getopt is available
  ARGS=`getopt --name "$PROG" --long help,output:,verbose --options ho:v -- "$@"`
else
  # Original getopt is available (no long option names, no whitespace, no sorting)
  ARGS=`getopt ho:v "$@"`
fi
if [ $? -ne 0 ]; then
  echo "$PROG: usage error (use -h for help)" >&2
  exit 2
fi
eval set -- $ARGS

while [ $# -gt 0 ]; do
    case "$1" in
        -h | --help)     HELP=yes;;
        -o | --output)   OUTFILE="$2"; shift;;
        -v | --verbose)  VERBOSE=yes;;
        --)              shift; break;; # end of options
    esac
    shift
done

if [ $# -gt 0 ]; then
  # Remaining parameters can be processed
  for ARG in "$@"; do
    echo "$PROG: argument: $ARG"
  done
fi

echo "$PROG: verbose: $VERBOSE"
echo "$PROG: output: $OUTFILE"
echo "$PROG: help: $HELP"

Этот пример можно загрузить с https://gist.github.com/hoylen/6607180

Таблица сравнения в Запись в Википедии о getopts сравнивает различные функции.

14 голосов
/ 28 апреля 2010

Используйте getopts (с "s").

Согласно Bash FAQ 35 :

Если это не версия от util-linux и вы не используете расширенный режим, никогда не используйте getopt (1). getopt не может обрабатывать пустые строки аргументов или аргументы со встроенным пробелом. Пожалуйста, забудьте, что это когда-либо существовало.

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

1 голос
/ 07 октября 2011

Встроенная функция Bash getopts может использоваться для переноса коротких и длинных параметров, см .:

Использование getopts в сценарии оболочки bash для получения параметров длинной и короткой командной строки

0 голосов
/ 28 апреля 2010

Базовый синтаксис для getopt является кроссплатформенным.

getopt vi: -v -i 100 file
...