getopt
и getopts
- разные звери, и люди, кажется, немного не понимают, что они делают. getopts
- это встроенная команда bash
для обработки параметров командной строки в цикле и присвоения каждой найденной опции и значения по очереди встроенным переменным, чтобы вы могли в дальнейшем их обрабатывать. getopt
, однако, является внешней служебной программой, и на самом деле она не обрабатывает ваши параметры за вас так, как, например, bash getopts
, модуль Perl Getopt
или модули Python _8 _ / _ 9_. Все, что делает getopt
, - это канонизирует переданные параметры, т. Е. Преобразует их в более стандартную форму, чтобы сценарию оболочки было легче их обработать. Например, приложение getopt
может преобразовать следующее:
myscript -ab infile.txt -ooutfile.txt
в это:
myscript -a -b -o outfile.txt infile.txt
Вы должны сами выполнить фактическую обработку. Вам совсем не обязательно использовать getopt
, если вы накладываете различные ограничения на способ указания опций:
- только один вариант для каждого аргумента;
- все параметры идут перед позиционными параметрами (т.е. аргументами, не являющимися параметрами);
- для параметров со значениями (например,
-o
выше) значение должно идти как отдельный аргумент (после пробела).
Зачем использовать getopt
вместо getopts
? Основная причина в том, что только GNU getopt
предоставляет вам поддержку параметров командной строки с длинными именами. 1 (GNU getopt
используется по умолчанию в Linux. Mac OS X и FreeBSD поставляются с базовым и не очень -полезно getopt
, но можно установить версию GNU; см. ниже.)
Например, вот пример использования GNU getopt
из моего скрипта javawrap
:
# NOTE: This requires GNU getopt. On Mac OS X and FreeBSD, you have to install this
# separately; see below.
TEMP=`getopt -o vdm: --long verbose,debug,memory:,debugfile:,minheap:,maxheap: \
-n 'javawrap' -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
VERBOSE=false
DEBUG=false
MEMORY=
DEBUGFILE=
JAVA_MISC_OPT=
while true; do
case "$1" in
-v | --verbose ) VERBOSE=true; shift ;;
-d | --debug ) DEBUG=true; shift ;;
-m | --memory ) MEMORY="$2"; shift 2 ;;
--debugfile ) DEBUGFILE="$2"; shift 2 ;;
--minheap )
JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MinHeapFreeRatio=$2"; shift 2 ;;
--maxheap )
JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MaxHeapFreeRatio=$2"; shift 2 ;;
-- ) shift; break ;;
* ) break ;;
esac
done
Это позволяет вам указывать такие параметры, как --verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt"
или аналогичные. Результатом вызова getopt
является канонизация параметров --verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"
, чтобы вам было легче их обрабатывать. Заключение в кавычки "$1"
и "$2"
важно, поскольку оно гарантирует правильную обработку аргументов с пробелами.
Если вы удалите первые 9 строк (все до eval set
строки), код будет по-прежнему работать! Однако ваш код будет более разборчивым в том, какие типы параметров он принимает: в частности, вам нужно будет указать все параметры в «канонической» форме, описанной выше. Однако с использованием getopt
вы можете группировать однобуквенные параметры, использовать более короткие однозначные формы длинных параметров, использовать стиль --file foo.txt
или --file=foo.txt
, использовать стиль -m 4096
или -m4096
, смешивать параметры и не параметры в любой порядок и т. д. getopt
также выводит сообщение об ошибке, если обнаруживаются нераспознанные или неоднозначные параметры.
ПРИМЕЧАНИЕ: на самом деле существует две совершенно разные версии getopt
, базовая getopt
и GNU getopt
, с разными функциями и разными соглашениями о вызовах. 2 Basic getopt
совершенно не работает: он не только не обрабатывает длинные параметры, он также не может обрабатывать даже встроенные пробелы внутри аргументов или пустые аргументы, тогда как getopts
делает это правильно. Приведенный выше код не будет работать в базовой версии getopt
. GNU getopt
устанавливается по умолчанию в Linux, но в Mac OS X и FreeBSD его нужно устанавливать отдельно. В Mac OS X установите MacPorts (http://www.macports.org), а затем выполните sudo port install getopt
, чтобы установить GNU getopt
(обычно в /opt/local/bin
) и убедитесь, что /opt/local/bin
находится в пути вашей оболочки перед /usr/bin
. На FreeBSD установите misc/getopt
.
Краткое руководство по изменению примера кода для вашей собственной программы: из первых нескольких строк все является «шаблоном», который должен оставаться неизменным, за исключением строки, которая вызывает getopt
. Вы должны изменить имя программы после -n
, указать короткие параметры после -o
и длинные параметры после --long
. Ставьте двоеточие после параметров, принимающих значение.
Наконец, если вы видите код, в котором всего set
вместо eval set
, он был написан для BSD getopt
. Вы должны изменить его, чтобы использовать стиль eval set
, который отлично работает с обеими версиями getopt
, в то время как простой set
не работает правильно с GNU getopt
.
1 На самом деле getopts
в ksh93
поддерживает параметры с длинными именами, но эта оболочка используется не так часто, как bash
. В zsh
используйте zparseopts
, чтобы получить эту функциональность.
2 Технически «GNU getopt
» - неправильное употребление; эта версия была написана для Linux, а не для проекта GNU. Однако он следует всем соглашениям GNU, и обычно используется термин «GNU getopt
» (например, во FreeBSD).
person
Urban Vagabond
schedule
30.10.2011