getopt
і getopts
це різні звірі, і люди, здається, мають трохи нерозуміння того, що роблять. getopts
- це вбудована команда для bash
обробки параметрів командного рядка в циклі та присвоєння кожному знайденому параметру та значенню по черзі вбудованим змінним, тож ви можете їх далі обробляти. getopt
однак це зовнішня утиліта, і вона насправді не обробляє ваші параметри для вас так, як, наприклад, bash getopts
, Perl Getopt
модуль або Python optparse
/ argparse
модулі. Все, що потрібно getopt
, - це канонізувати параметри, що передаються - тобто перетворити їх у більш стандартну форму, щоб сценарій оболонки був легше обробляти їх. Наприклад, програма getopt
може конвертувати наступне:
myscript -ab infile.txt -ooutfile.txt
в це:
myscript -a -b -o outfile.txt infile.txt
Ви повинні зробити власне обробку самостійно. Вам взагалі не доведеться користуватися, getopt
якщо ви робите різні обмеження щодо способу вказівки параметрів:
- поставити лише один варіант на аргумент;
- всі параметри переходять до будь-яких позиційних параметрів (тобто аргументів необов'язкових);
- для параметрів зі значеннями (наприклад,
-o
вище) значення має бути окремим аргументом (після пробілу).
Навіщо використовувати getopt
замість getopts
? Основна причина полягає в тому, що тільки GNU getopt
надає вам підтримку для давно названих параметрів командного рядка. 1 ( getopt
за замовчуванням у Linux є GNU . 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
, basic 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).