Использование getopts для обработки длинных и коротких параметров командной строки - PullRequest
369 голосов
/ 31 декабря 2008

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

Я знаю, что getopts можно использовать, но, как и в Perl, я не смог сделать то же самое с shell.

Любые идеи о том, как это можно сделать, чтобы я мог использовать такие параметры, как:

./shell.sh --copyfile abc.pl /tmp/
./shell.sh -c abc.pl /tmp/

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

Ответы [ 32 ]

280 голосов
/ 31 октября 2011

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 (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).

270 голосов
/ 31 декабря 2008

Существует три варианта реализации:

  • Встроенный Bash getopts. Это не поддерживает длинные имена параметров с префиксом двойной тире. Поддерживаются только односимвольные параметры.

  • BSD UNIX реализация отдельной команды getopt (именно это использует MacOS). Это также не поддерживает длинные опции.

  • автономная реализация GNU getopt. GNU getopt(3) (используется командной строкой getopt(1) в Linux) поддерживает синтаксический анализ длинных параметров.


Некоторые другие ответы показывают решение для использования встроенного в bash getopts для имитации длинных опций. Это решение фактически делает короткую опцию, чей символ "-". Таким образом, вы получаете «-» в качестве флага. Затем все, что следует за этим, становится OPTARG, и вы проверяете OPTARG с вложенным case.

Это умно, но с оговорками:

  • getopts не может применить опцию спецификации. Он не может возвращать ошибки, если пользователь указывает неверную опцию. При разборе OPTARG вы должны выполнить собственную проверку ошибок.
  • OPTARG используется для длинного имени опции, что усложняет использование, когда у самой длинной опции есть аргумент. Вы заканчиваете тем, что должны были кодировать это самостоятельно как дополнительный случай.

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

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

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

#!/usr/bin/env bash 
optspec=":hv-:"
while getopts "$optspec" optchar; do
    case "${optchar}" in
        -)
            case "${OPTARG}" in
                loglevel)
                    val="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
                    echo "Parsing option: '--${OPTARG}', value: '${val}'" >&2;
                    ;;
                loglevel=*)
                    val=${OPTARG#*=}
                    opt=${OPTARG%=$val}
                    echo "Parsing option: '--${opt}', value: '${val}'" >&2
                    ;;
                *)
                    if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then
                        echo "Unknown option --${OPTARG}" >&2
                    fi
                    ;;
            esac;;
        h)
            echo "usage: $0 [-v] [--loglevel[=]<value>]" >&2
            exit 2
            ;;
        v)
            echo "Parsing option: '-${optchar}'" >&2
            ;;
        *)
            if [ "$OPTERR" != 1 ] || [ "${optspec:0:1}" = ":" ]; then
                echo "Non-option argument: '-${OPTARG}'" >&2
            fi
            ;;
    esac
done

После копирования в исполняемый файл с именем = getopts_test.sh в текущем рабочем каталоге можно получить вывод, подобный

$ ./getopts_test.sh
$ ./getopts_test.sh -f
Non-option argument: '-f'
$ ./getopts_test.sh -h
usage: code/getopts_test.sh [-v] [--loglevel[=]<value>]
$ ./getopts_test.sh --help
$ ./getopts_test.sh -v
Parsing option: '-v'
$ ./getopts_test.sh --very-bad
$ ./getopts_test.sh --loglevel
Parsing option: '--loglevel', value: ''
$ ./getopts_test.sh --loglevel 11
Parsing option: '--loglevel', value: '11'
$ ./getopts_test.sh --loglevel=11
Parsing option: '--loglevel', value: '11'

Очевидно, что getopts не выполняет ни проверки OPTERR, ни анализа параметров-аргументов для длинных параметров. Приведенный выше фрагмент скрипта показывает, как это можно сделать вручную. Основной принцип также работает в оболочке Debian Almquist («тире»). Обратите внимание на особый случай:

getopts -- "-:"  ## without the option terminator "-- " bash complains about "-:"
getopts "-:"     ## this works in the Debian Almquist shell ("dash")

Обратите внимание, что, как указывает GreyCat из-за http://mywiki.wooledge.org/BashFAQ, этот прием использует нестандартное поведение оболочки, которое позволяет параметру-аргументу (то есть имени файла в «-f filename») быть объединены с опцией (как в "-ffilename"). Стандарт POSIX гласит, что между ними должен быть пробел, который в случае "- longoption" завершит разбор параметров и превратит все longoptions в неопционные аргументы.

148 голосов
/ 31 декабря 2008

Встроенная команда getopts по-прежнему, AFAIK, ограничена только односимвольными параметрами.

Существует (или использовалась) внешняя программа getopt, которая реорганизовала бы набор параметров таким образом, чтобы их было легче анализировать. Вы можете адаптировать этот дизайн для обработки длинных вариантов тоже. Пример использования:

aflag=no
bflag=no
flist=""
set -- $(getopt abf: "$@")
while [ $# -gt 0 ]
do
    case "$1" in
    (-a) aflag=yes;;
    (-b) bflag=yes;;
    (-f) flist="$flist $2"; shift;;
    (--) shift; break;;
    (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
    (*)  break;;
    esac
    shift
done

# Process remaining non-option arguments
...

Вы можете использовать аналогичную схему с командой getoptlong.

Обратите внимание, что основным недостатком внешней программы getopt является сложность обработки аргументов с пробелами в них и их точного сохранения. Вот почему встроенный getopts лучше, хотя и ограничен тем, что обрабатывает только однобуквенные опции.

74 голосов
/ 08 марта 2011

Вот пример, который на самом деле использует getopt с длинными параметрами:

aflag=no
bflag=no
cargument=none

# options may be followed by one colon to indicate they have a required argument
if ! options=$(getopt -o abc: -l along,blong,clong: -- "$@")
then
    # something went wrong, getopt will put out an error message for us
    exit 1
fi

set -- $options

while [ $# -gt 0 ]
do
    case $1 in
    -a|--along) aflag="yes" ;;
    -b|--blong) bflag="yes" ;;
    # for options with required arguments, an additional shift is required
    -c|--clong) cargument="$2" ; shift;;
    (--) shift; break;;
    (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
    (*) break;;
    esac
    shift
done
42 голосов
/ 12 февраля 2015

Длинные опции могут быть проанализированы стандартным getopts встроенным в качестве «аргументов» для - «опции»

Это переносная и нативная оболочка POSIX - никаких внешних программ или ошибок не требуется.

Это руководство реализует длинные параметры в качестве аргументов для параметра -, поэтому --alpha рассматривается getopts как - с аргументом alpha, а --bravo=foo отображается как - с аргументом bravo=foo. Истинный аргумент может быть получен простой заменой: ${OPTARG#*=}.

В этом примере -b (и его полная форма, --bravo) имеет обязательную опцию (обратите внимание на ручную реконструкцию принудительного применения для полной формы). Не булевы опции для длинных аргументов следуют после знака равенства, например --bravo=foo (разделители пробела для длинных опций будет сложно реализовать).

Поскольку в нем используется getopts, это решение поддерживает использование, например cmd -ac --bravo=foo -d FILE (которое объединяет параметры -a и - c и чередует длинные параметры со стандартными параметрами), тогда как большинство других ответов здесь либо затрудняются, либо не выполняются что.

while getopts ab:c-: arg; do
  case $arg in
    a )  ARG_A=true ;;
    b )  ARG_B="$OPTARG" ;;
    c )  ARG_C=true ;;
    - )  LONG_OPTARG="${OPTARG#*=}"
         case $OPTARG in
           alpha    )  ARG_A=true ;;
           bravo=?* )  ARG_B="$LONG_OPTARG" ;;
           bravo*   )  echo "No arg for --$OPTARG option" >&2; exit 2 ;;
           charlie  )  ARG_C=true ;;
           alpha* | charlie* )
                       echo "No arg allowed for --$OPTARG option" >&2; exit 2 ;;
           '' )        break ;; # "--" terminates argument processing
           * )         echo "Illegal option --$OPTARG" >&2; exit 2 ;;
         esac ;;
    \? ) exit 2 ;;  # getopts already reported the illegal option
  esac
done
shift $((OPTIND-1)) # remove parsed options and args from $@ list

Когда аргумент является тире (-), он имеет еще два компонента: имя флага и (необязательно) его аргумент. Я разграничиваю их стандартным способом, которым будет любая команда, с первым знаком равенства (=). Таким образом, $LONG_OPTARG - это просто содержимое $OPTARG без имени флага или знака равенства.

Внутренний case реализует длинные опции вручную, поэтому он требует некоторого обслуживания:

  • bravo=? соответствует --bravo=foo, но не --bravo= (примечание: case останавливается после первого матча)
  • bravo* следует, отмечая отсутствующий обязательный аргумент в --bravo и --bravo=
  • alpha* | charlie* перехватывает аргументы, заданные опциям, которые их не поддерживают
  • '' присутствует для поддержки не-опций, которые начинаются с тире
  • * перехватывает все другие длинные опции и воссоздает ошибку, выданную getopts для недопустимой опции

Вам не обязательно нужны все эти предметы домашнего обихода. Например, возможно, вы хотите, чтобы --bravo имел необязательный аргумент (который -b не может поддерживать из-за ограничения в getopts). Просто удалите =? и соответствующий сбой, а затем позвоните ${ARG_B:=$DEFAULT_ARG_B} при первом использовании $ARG_B.


Чтобы принимать длинные опции с аргументами, разделенными пробелами, вам понадобится (достаточно надежно) eval:

           bravo=?* )  ARG_B="$LONG_OPTARG" ;;
           bravo )     eval "ARG_B=\"\$$OPTIND\""
                       if [ -z "$ARG_B" ]; then
                         echo "No arg for --$OPTARG option" >&2; exit 2
                       fi
                       OPTIND=$((OPTIND+1)) ;;
           bravo*   )  echo "No arg for --$OPTARG option" >&2; exit 2 ;;

В этом дополнительном предложении, добавленном непосредственно после версии присвоения =, выполняется eval для интерпретации значения параметра после интерпретируемой в то время опции. Bash может сделать это более чисто, используя косвенное расширение , ARG_B="${!OPTIND}", а Zsh может сделать это с расширением параметра P flag , ARGB="${(P)OPTIND}", но необходим eval быть полностью переносимым POSIX. $OPTIND - это число, относящееся к следующему аргументу оболочки, скажем, $2 (значение $1 равно --bravo). eval будет тогда интерпретировать ARG_B="$2", и поскольку это заключено в кавычки, это безопасно от злоупотреблений (я не мог найти способ обмануть его, чтобы сделать что-то неуместное).

Гарантия непустого значения нетривиальна и требует его фактической проверки, поэтому в этом случае мы получаем условную ошибку и приводим к фатальной ошибке. Если вы позволите ему быть пустым, вам нужно будет условно увеличить значение $OPTIND или запустить бесконечный цикл. [ $# -gt $OPTIND ] && OPTIND=$((OPTIND+1)) должен сделать.

Последняя часть этого дополнительного предложения увеличивается на $OPTIND, чтобы правильно воспринять аргумент опции и перейти к следующей опции.

32 голосов
/ 15 мая 2009

Взгляните на shFlags , которая представляет собой переносимую библиотеку оболочки (имеется в виду sh, bash, dash, ksh, zsh в Linux, Solaris и т.

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

Вот простое Hello, world! с использованием shFlag :

#!/bin/sh

# source shflags from current directory
. ./shflags

# define a 'name' command-line string flag
DEFINE_string 'name' 'world' 'name to say hello to' 'n'

# parse the command-line
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"

# say hello
echo "Hello, ${FLAGS_name}!"

Для ОС, которые имеют расширенный getopt, который поддерживает длинные опции (например, Linux), вы можете сделать:

$ ./hello_world.sh --name Kate
Hello, Kate!

В остальном вы должны использовать короткую опцию:

$ ./hello_world.sh -n Kate
Hello, Kate!

Добавить новый флаг так же просто, как добавить новый DEFINE_ call.

30 голосов
/ 21 сентября 2012

Использование getopts с короткими / длинными параметрами и аргументами


Работает со всеми комбинациями, например:

  • foobar -f --bar
  • foobar --foo -b
  • foobar -bf --bar --foobar
  • foobar -fbFBAshorty --bar -FB --arguments = longhorn
  • foobar -fA "texty shorty" -B --arguments = "text longhorn"
  • bash foobar -F --barfoo
  • sh foobar -B --foobar - ...
  • bash ./foobar -F --bar

Некоторые объявления для этого примера

Options=$@
Optnum=$#
sfoo='no '
sbar='no '
sfoobar='no '
sbarfoo='no '
sarguments='no '
sARG=empty
lfoo='no '
lbar='no '
lfoobar='no '
lbarfoo='no '
larguments='no '
lARG=empty

Как будет выглядеть функция использования

function _usage() 
{
  ###### U S A G E : Help and ERROR ######
  cat <<EOF
   foobar $Options
  $*
          Usage: foobar <[options]>
          Options:
                  -b   --bar            Set bar to yes    ($foo)
                  -f   --foo            Set foo to yes    ($bart)
                  -h   --help           Show this message
                  -A   --arguments=...  Set arguments to yes ($arguments) AND get ARGUMENT ($ARG)
                  -B   --barfoo         Set barfoo to yes ($barfoo)
                  -F   --foobar         Set foobar to yes ($foobar)
EOF
}

[ $# = 0 ] && _usage "  >>>>>>>> no options given "

getops с длинными / короткими флагами и длинными аргументами

while getopts ':bfh-A:BF' OPTION ; do
  case "$OPTION" in
    b  ) sbar=yes                       ;;
    f  ) sfoo=yes                       ;;
    h  ) _usage                         ;;   
    A  ) sarguments=yes;sARG="$OPTARG"  ;;
    B  ) sbarfoo=yes                    ;;
    F  ) sfoobar=yes                    ;;
    -  ) [ $OPTIND -ge 1 ] && optind=$(expr $OPTIND - 1 ) || optind=$OPTIND
         eval OPTION="\$$optind"
         OPTARG=$(echo $OPTION | cut -d'=' -f2)
         OPTION=$(echo $OPTION | cut -d'=' -f1)
         case $OPTION in
             --foo       ) lfoo=yes                       ;;
             --bar       ) lbar=yes                       ;;
             --foobar    ) lfoobar=yes                    ;;
             --barfoo    ) lbarfoo=yes                    ;;
             --help      ) _usage                         ;;
             --arguments ) larguments=yes;lARG="$OPTARG"  ;; 
             * )  _usage " Long: >>>>>>>> invalid options (long) " ;;
         esac
       OPTIND=1
       shift
      ;;
    ? )  _usage "Short: >>>>>>>> invalid options (short) "  ;;
  esac
done

выход

##################################################################
echo "----------------------------------------------------------"
echo "RESULT short-foo      : $sfoo                                    long-foo      : $lfoo"
echo "RESULT short-bar      : $sbar                                    long-bar      : $lbar"
echo "RESULT short-foobar   : $sfoobar                                 long-foobar   : $lfoobar"
echo "RESULT short-barfoo   : $sbarfoo                                 long-barfoo   : $lbarfoo"
echo "RESULT short-arguments: $sarguments  with Argument = \"$sARG\"   long-arguments: $larguments and $lARG"

Объединение всего вышеперечисленного в единый сценарий

#!/bin/bash
# foobar: getopts with short and long options AND arguments

function _cleanup ()
{
  unset -f _usage _cleanup ; return 0
}

## Clear out nested functions on exit
trap _cleanup INT EXIT RETURN

###### some declarations for this example ######
Options=$@
Optnum=$#
sfoo='no '
sbar='no '
sfoobar='no '
sbarfoo='no '
sarguments='no '
sARG=empty
lfoo='no '
lbar='no '
lfoobar='no '
lbarfoo='no '
larguments='no '
lARG=empty

function _usage() 
{
  ###### U S A G E : Help and ERROR ######
  cat <<EOF
   foobar $Options
   $*
          Usage: foobar <[options]>
          Options:
                  -b   --bar            Set bar to yes    ($foo)
                    -f   --foo            Set foo to yes    ($bart)
                      -h   --help           Show this message
                  -A   --arguments=...  Set arguments to yes ($arguments) AND get ARGUMENT ($ARG)
                  -B   --barfoo         Set barfoo to yes ($barfoo)
                  -F   --foobar         Set foobar to yes ($foobar)
EOF
}

[ $# = 0 ] && _usage "  >>>>>>>> no options given "

##################################################################    
#######  "getopts" with: short options  AND  long options  #######
#######            AND  short/long arguments               #######
while getopts ':bfh-A:BF' OPTION ; do
  case "$OPTION" in
    b  ) sbar=yes                       ;;
    f  ) sfoo=yes                       ;;
    h  ) _usage                         ;;   
    A  ) sarguments=yes;sARG="$OPTARG"  ;;
    B  ) sbarfoo=yes                    ;;
    F  ) sfoobar=yes                    ;;
    -  ) [ $OPTIND -ge 1 ] && optind=$(expr $OPTIND - 1 ) || optind=$OPTIND
         eval OPTION="\$$optind"
         OPTARG=$(echo $OPTION | cut -d'=' -f2)
         OPTION=$(echo $OPTION | cut -d'=' -f1)
         case $OPTION in
             --foo       ) lfoo=yes                       ;;
             --bar       ) lbar=yes                       ;;
             --foobar    ) lfoobar=yes                    ;;
             --barfoo    ) lbarfoo=yes                    ;;
             --help      ) _usage                         ;;
               --arguments ) larguments=yes;lARG="$OPTARG"  ;; 
             * )  _usage " Long: >>>>>>>> invalid options (long) " ;;
         esac
       OPTIND=1
       shift
      ;;
    ? )  _usage "Short: >>>>>>>> invalid options (short) "  ;;
  esac
done
22 голосов
/ 10 марта 2011

Другой способ ...

# translate long options to short
for arg
do
    delim=""
    case "$arg" in
       --help) args="${args}-h ";;
       --verbose) args="${args}-v ";;
       --config) args="${args}-c ";;
       # pass through anything else
       *) [[ "${arg:0:1}" == "-" ]] || delim="\""
           args="${args}${delim}${arg}${delim} ";;
    esac
done
# reset the translated args
eval set -- $args
# now we can process with getopt
while getopts ":hvc:" opt; do
    case $opt in
        h)  usage ;;
        v)  VERBOSE=true ;;
        c)  source $OPTARG ;;
        \?) usage ;;
        :)
        echo "option -$OPTARG requires an argument"
        usage
        ;;
    esac
done
18 голосов
/ 04 августа 2011

Я вроде как решил:

# A string with command options
options=$@

# An array with all the arguments
arguments=($options)

# Loop index
index=0

for argument in $options
  do
    # Incrementing index
    index=`expr $index + 1`

    # The conditions
    case $argument in
      -a) echo "key $argument value ${arguments[index]}" ;;
      -abc) echo "key $argument value ${arguments[index]}" ;;
    esac
  done

exit;

Я тупой или что? getopt и getopts настолько сбивают с толку.

...