Существуют две версии команды 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 сравнивает различные функции.