Як обробляти комутатори в сценарії оболонки?


17

Є деякі вбудовані інструменти , які розпізнають -xі --xxxxяк перемикачі, а не аргументи, або ж ви повинні пройти через всі вхідні змінні, тест на тир, а потім розібрати аргументи в подальшому?

Відповіді:


16

Використовуйте getopts.

Він досить портативний, як і в специфікації POSIX. На жаль, він не підтримує довгі варіанти.

Дивіться також цю getopts підручник з люб'язності вікі-хакер-хакерів і це питання від stackoverflow.

Якщо вам потрібні лише короткі параметри, типовою схемою використання getopts(з використанням беззвучного повідомлення про помилки) є:

# process arguments "$1", "$2", ... (i.e. "$@")
while getopts "ab:" opt; do
    case $opt in
    a) aflag=true ;; # Handle -a
    b) barg=$OPTARG ;; # Handle -b argument
    \?) ;; # Handle error: unknown option or missing required argument.
    esac
done

3
Слід зазначити, що getoptперед тим, як використовувати його, завжди слід перевіряти як GNU getopt, але все одно не слід користуватися ним, оскільки це все-таки getoptsбільш портативно (і взагалі приємніше). Якщо ви робите потреба назвати його по якій - то причини, називають його в GNU-певним чином, і переконайтеся , що GETOPT_COMPATIBLEце не в навколишньому середовищі.
Кріс Даун

Що робить товста кишка while getopts "ab:" opt?
користувач394

1
@ user394 Лист :після опції означає, що він вимагає аргументу. А :як перший символ означає придушити повідомлення про помилки.
jw013

22

Я припускаю, що ви використовуєте bash або подібне. Приклад:

all=false
long=false

while getopts ":hal" option; do
  case $option in
    h) echo "usage: $0 [-h] [-a] [-l] file ..."; exit ;;
    a) all=true ;;
    l) long=true ;;
    ?) echo "error: option -$OPTARG is not implemented"; exit ;;
  esac
done

# remove the options from the positional parameters
shift $(( OPTIND - 1 ))

ls_opts=()
$all && ls_opts+=( -a )
$long && ls_opts+=( -l )

# now, do it
ls "${ls_opts[@]}" "$@"

1
+1 для використання +=з масивом. Не знав, що ти можеш це зробити. Приємно!
Джеймс Снерінгер

5

Ви повинні написати цикл для розбору параметрів. Дійсно, ви можете використовувати getoptsкоманду, щоб зробити це легко.

Це простий приклад зі getoptsсторінки керівництва:

aflag=
bflag=
while getopts ab: name
do
    case $name in
    a)    aflag=1;;
    b)    bflag=1
          bval="$OPTARG";;
    ?)    printf "Usage: %s: [-a] [-b value] args\n" $0
          exit 2;;
    esac
done
if [ ! -z "$aflag" ]; then
    printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
    printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"

2

Нещодавно я написав сценарій для роботи, яка була універсальною і дозволяла виконувати різні види комутаторів у будь-якому порядку. Я не можу розкрити повний сценарій з очевидних юридичних причин (не кажучи вже про те, що на даний момент у мене його немає), але ось його м'ясо .. Ви можете помістити його в підпрограму і зателефонувати в кінці вашого сценарію:

options () {

    if [ -n "$1" ]; then # test if any arguments passed - $1 will always exist
        while (( "$#" )); do  # process ALL arguments
            if [ "$1" = ^-t$ ]; then # -t short for "test"
                # do something here THEN shift the argument
                # shift removes it from $@ and reduces $# by
                # one if you supply no argument
                shift

            # we can also process multiple arguments at once
            elif [[ "$1" =~ ^--test=[:alnum:]{1,8}$ ]] && [[ "$2" =~ ^-t2$ ]] && [[ -n "$3" ]]; then # check for 3 arguments
                # do something more then remove them ALL from the arg list    
                shift 3
            else
                echo "No matching arguments!"
                echo "Usage: [script options list here]"
            fi
        done
    else
        echo "Usage: [script options list here]"
        exit 0
    fi
}

options "$@" # run options and loop through/process ALL arguments

Я рекомендую обмежити ваш скрипт bash менше 400 рядків / 15 К символів; мій вищезгаданий сценарій переріс цей розмір і надто важко було працювати над. Я почав її переписувати в Perl, що набагато краще підходить для виконання завдання. Майте це на увазі, коли ви працюєте над своїми сценаріями в bash. Bash чудово підходить для невеликих сценаріїв та онлайнів, але все, що складніше, і вам краще написати це на Perl.

Зауважте, я не перевіряв вищесказане, тому, ймовірно, це не працює, але ви отримуєте з цього загальну думку.


Те, як ви optionsв кінці телефонуєте, невірне, воно повернеться -bash: syntax error near unexpected token $@. Називай це як options "$@".
Кріс Даун

Так, я змішав Перл і Баша. Виправлено.
маячка

Ця whileумова не повинна бути (($#))замість цього?
манатура

Для чого вам потрібні два набори дужок $#? Редагувати: ти маєш рацію. Виправлено цеwhile (( "$#" ))
маяк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.