Приклад того, як використовувати getopts в bash


345

Я хочу викликати myscriptфайл таким чином:

$ ./myscript -s 45 -p any_string

або

$ ./myscript -h  #should display help
$ ./myscript     #should display help

Мої вимоги:

  • getopt тут, щоб отримати вхідні аргументи
  • перевірте, що -sіснує, якщо не повернути помилку
  • перевірте, чи є значення після -s45 або 90
  • перевірте, чи -pіснує і чи є вхідний рядок після
  • якщо користувач входить ./myscript -hабо просто ./myscriptпотім відображає довідку

Я спробував поки що цей код:

#!/bin/bash
while getopts "h:s:" arg; do
  case $arg in
    h)
      echo "usage" 
      ;;
    s)
      strength=$OPTARG
      echo $strength
      ;;
  esac
done

Але з цим кодом я отримую помилки. Як це зробити з Bash і getopt?


2
Опції повинні бути необов'язковими. Якщо вам потрібно значення , вказане -s, зробити його позиційне аргумент: ./myscript 45 anystring.
Чепнер

@chepner$./myscript -s 45 -p any_string
MOHAMED

Добре, якщо -pнасправді є варіант (тобто ваша програма може продовжуватися, якщо її немає). У цьому випадку ./myscript 45 -p any_string. (Я думаю, що getoptможна обробляти змішані параметри та позиційні аргументи, тоді як bashвбудована команда getoptsвимагає, щоб всі параметри позиції були розміщені після опцій.)
Чепнер

Відповіді:


513
#!/bin/bash

usage() { echo "Usage: $0 [-s <45|90>] [-p <string>]" 1>&2; exit 1; }

while getopts ":s:p:" o; do
    case "${o}" in
        s)
            s=${OPTARG}
            ((s == 45 || s == 90)) || usage
            ;;
        p)
            p=${OPTARG}
            ;;
        *)
            usage
            ;;
    esac
done
shift $((OPTIND-1))

if [ -z "${s}" ] || [ -z "${p}" ]; then
    usage
fi

echo "s = ${s}"
echo "p = ${p}"

Приклад виконання:

$ ./myscript.sh
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -h
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s "" -p ""
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s 10 -p foo
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s 45 -p foo
s = 45
p = foo

$ ./myscript.sh -s 90 -p bar
s = 90
p = bar

19
У дзвінку getopts, чому там є провідна кишка? Коли після "h" після нього є двокрапка?
e40

7
usage()Справді слід повернути 1?
Пітікос

6
@Pithikos Добре. Здоровий глузд підказує мені, що при посиланні на -hнього слід повернутися 0, після натискання на неіснуючий прапор він повинен повернутися >0(заради простоти я не розмежував ці випадки, і ніхто не змушує вас друкувати текст використання в останньому випадку) . Я бачив програми, які завжди повертаються != 0, хоча навіть на -h/--help. Можливо, я повинен оновити фрагмент, якщо люди використовують це як котельну панель (сподіваюся, що ні)?
Адріан Фрюхвірт

1
@ A.Danischewski Це за ( getopts') дизайном, немає такого поняття, як "необов'язкові аргументи" з getopts. Аналізатор просто не може знати, чи наступний маркер є аргументом поточної опції або опцією сам по собі, оскільки -pможе бути призначеним значенням. Ви можете зламати це, якщо ви абсолютно знаєте, що параметр параметра не може виглядати як інший дійсний параметр, так, але можна сказати, що в POSIX не визначені необов'язкові аргументи.
Адріан Фрюхвітрт

4
@ user1011471 Ви праві! Фігурні дужки, так би мовити, просто допомагають bashлексеру у визначенні змінних. Вони в багатьох випадках непотрібні, і те, що я завжди їх використовую, - лише питання особистого стилю кодування. Мені легше (і красивіше) просто завжди використовувати їх замість того, щоб запам'ятовувати правила розбору щодо неоднозначності. Приблизно те саме, чому можна писати if (foo) { bar; }замість мови if (foo) bar;в стилі С (естетика та / або уникати дурних помилок).
Адріан Фрюхвітрт

109

Проблема з оригінальним кодом полягає в тому, що:

  • h:очікує параметр, де він не повинен, тому змініть його на просто h(без двокрапки)
  • щоб очікувати -p any_string, вам потрібно додати p:до списку аргументів

В основному :після параметра означає, що він вимагає аргументу.


Основний синтаксис getopts: (див. man bash:):

getopts OPTSTRING VARNAME [ARGS...]

де:

  • OPTSTRING рядок із переліком очікуваних аргументів,

    • h- перевірка на вибір -h без параметрів; дає помилку в непідтримуваних опціях;
    • h:- перевірити параметр -h з параметром; видає помилки в непідтримуваних параметрах;
    • abc- перевірка опцій -a, -b, -c; видає помилки в непідтримуваних параметрах;
    • :abc- перевірка опцій -a, -b, -c; замовчує помилки на непідтримуваних опціях;

      Примітки. Іншими словами, двокрапка перед параметрами дозволяє обробляти помилки у вашому коді. Змінна міститиме ?у випадку непідтримуваного параметра, :у разі відсутнього значення.

  • OPTARG - встановлюється поточне значення аргументу,

  • OPTERR - вказує, чи повинен Bash відображати повідомлення про помилки.

Таким кодом може бути:

#!/usr/bin/env bash
usage() { echo "$0 usage:" && grep " .)\ #" $0; exit 0; }
[ $# -eq 0 ] && usage
while getopts ":hs:p:" arg; do
  case $arg in
    p) # Specify p value.
      echo "p is ${OPTARG}"
      ;;
    s) # Specify strength, either 45 or 90.
      strength=${OPTARG}
      [ $strength -eq 45 -o $strength -eq 90 ] \
        && echo "Strength is $strength." \
        || echo "Strength needs to be either 45 or 90, $strength found instead."
      ;;
    h | *) # Display help.
      usage
      exit 0
      ;;
  esac
done

Приклад використання:

$ ./foo.sh 
./foo.sh usage:
    p) # Specify p value.
    s) # Specify strength, either 45 or 90.
    h | *) # Display help.
$ ./foo.sh -s 123 -p any_string
Strength needs to be either 45 or 90, 123 found instead.
p is any_string
$ ./foo.sh -s 90 -p any_string
Strength is 90.
p is any_string

Дивіться: Підручник з невеликими геттоптами на Вікі Bash Hackers


2
Змініть функцію використання для цього: usage() { echo "$0 usage:" && grep "[[:space:]].)\ #" $0 | sed 's/#//' | sed -r 's/([a-z])\)/-\1/'; exit 0; }. Він припадає лише на один символ пробілу перед параметром літери, видаляє # з коментаря і попереджує "-" перед буквою, що робить його зрозумілішим для команди.
poagester

2
@kenorb: Колон перед параметрами не ігнорує непідтримувані параметри, але замовчує помилки від bash і дозволяє вам обробляти це у своєму коді. Змінна буде містити "?" у випадку непідтримуваного параметра та ':' у разі відсутнього значення.
Hynek -Pichi- Vychodil

1
Дякую за детальні документи, не зміг отримати :право, поки я не побачив ці замітки. Нам потрібно додати :параметр, де ми очікуємо аргумент.
Авхан

51

Використовуйте getopt

Чому getopt?

Щоб проаналізувати розроблені аргументи командного рядка, щоб уникнути плутанини та уточнити параметри, які ми розбираємо, щоб читач команд міг зрозуміти, що відбувається.

Що таке getopt?

getoptвикористовується для розбиття (розбору) параметрів командних рядків для легкого розбору процедур оболонки та для перевірки правових варіантів. Для цього він використовує getopt(3)підпрограми GNU .

getopt може мати такі типи варіантів.

  1. Варіанти без значення
  2. параметри ключ-значення пари

Примітка. У цьому документі під час пояснення синтаксису:

  • Все, що знаходиться всередині [], є необов’язковим параметром у синтаксисі / прикладах.
  • - це місце, яке означає, що його слід замінити фактичним значенням.

ЯК ВИКОРИСТОВУВАТИ getopt?

Синтаксис: Перша форма

getopt optstring parameters

Приклади:

# This is correct
getopt "hv:t::" "-v 123 -t123"  
getopt "hv:t::" "-v123 -t123"  # -v and 123 doesn't have whitespace

# -h takes no value.
getopt "hv:t::" "-h -v123"


# This is wrong. after -t can't have whitespace.
# Only optional params cannot have whitespace between key and value
getopt "hv:t::" "-v 123 -t 123"

# Multiple arguments that takes value.
getopt "h:v:t::g::" "-h abc -v 123 -t21"

# Multiple arguments without value
# All of these are correct
getopt "hvt" "-htv"
getopt "hvt" "-h -t -v"
getopt "hvt" "-tv -h"

Тут h, v, t - параметри, а -h -v -t - це те, як слід задавати параметри в командному рядку.

  1. 'h' - нецінна опція.
  2. 'v:' означає, що варіант -v має значення і є обов'язковим варіантом. ':' означає, що має значення.
  3. 't ::' означає, що варіант -t має значення, але необов’язковий. '::' означає необов’язковий.

У необов'язковій параметрі значення не може мати розділення пробілу з опцією. Так, у прикладі "-t123", -t - варіант 123 є значенням.

Синтаксис: Друга форма

getopt [getopt_options] [--] [optstring] [parameters]

Тут після getopt розбивається на п'ять частин

  • Сама команда, тобто getopt
  • Getopt_options, він описує, як аналізувати аргументи. параметри з одночасним тире, подвійні параметри тире.
  • -, відокремлює getopt_options від параметрів, які ви хочете проаналізувати, і дозволених коротких варіантів
  • Короткі варіанти, взяті відразу після - знайдені. Так само, як синтаксис першого формату.
  • Параметри, це параметри, які ви передали в програму. Параметри, які ви хочете розібрати і отримати фактичні значення, встановлені на них.

Приклади

getopt -l "name:,version::,verbose" -- "n:v::V" "--name=Karthik -version=5.2 -verbose"

Синтаксис: Третя форма

getopt [getopt_options] [-o options] [--] [optstring] [parameters]

Тут після getopt розбивається на п'ять частин

  • Сама команда, тобто getopt
  • Getopt_options, він описує, як аналізувати аргументи. параметри з одночасним тире, подвійні параметри тире.
  • Короткі варіанти, тобто -o або --options. Як і перший синтаксис Форми, але з опцією "-o" та перед "-" (подвійний тире).
  • -, відокремлює getopt_options від параметрів, які ви хочете проаналізувати, і дозволених коротких варіантів
  • Параметри, це параметри, які ви передали в програму. Параметри, які ви хочете розібрати і отримати фактичні значення, встановлені на них.

Приклади

getopt -l "name:,version::,verbose" -a -o "n:v::V" -- "-name=Karthik -version=5.2 -verbose"

GETOPT_OPTIONS

getopt_options змінює спосіб розбору парам командного рядка.

Нижче наведено деякі з getopt_options

Варіант: -l або --logoptions

Команда getopt має надати можливість розпізнавати багато символи. Кілька варіантів розділені комою.

Наприклад, --name=Karthikдовгий варіант, що надсилається в командному рядку. У методі getopt подібне використання довгих варіантів

getopt "name:,version" "--name=Karthik"

Оскільки вказано ім'я: опція повинна містити значення

Варіант: -a або - альтернативний

Команда getopt команда повинна дозволяти довгій опції мати один тире '-', а не подвійний тире '-'.

Наприклад, замість --name=Karthikвас можна було використовувати просто-name=Karthik

getopt "name:,version" "-name=Karthik"

Повний приклад сценарію з кодом:

#!/bin/bash

# filename: commandLine.sh
# author: @theBuzzyCoder

showHelp() {
# `cat << EOF` This means that cat should stop reading when EOF is detected
cat << EOF  
Usage: ./installer -v <espo-version> [-hrV]
Install Pre-requisites for EspoCRM with docker in Development mode

-h, -help,          --help                  Display help

-v, -espo-version,  --espo-version          Set and Download specific version of EspoCRM

-r, -rebuild,       --rebuild               Rebuild php vendor directory using composer and compiled css using grunt

-V, -verbose,       --verbose               Run script in verbose mode. Will print out each step of execution.

EOF
# EOF is found above and hence cat command stops reading. This is equivalent to echo but much neater when printing out.
}


export version=0
export verbose=0
export rebuilt=0

# $@ is all command line parameters passed to the script.
# -o is for short options like -v
# -l is for long options with double dash like --version
# the comma separates different long options
# -a is for long options with single dash like -version
options=$(getopt -l "help,version:,verbose,rebuild,dryrun" -o "hv:Vrd" -a -- "$@")

# set --:
# If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters 
# are set to the arguments, even if some of them begin with a ‘-’.
eval set -- "$options"

while true
do
case $1 in
-h|--help) 
    showHelp
    exit 0
    ;;
-v|--version) 
    shift
    export version=$1
    ;;
-V|--verbose)
    export verbose=1
    set -xv  # Set xtrace and verbose mode.
    ;;
-r|--rebuild)
    export rebuild=1
    ;;
--)
    shift
    break;;
esac
shift
done

Запуск цього файлу сценарію:

# With short options grouped together and long option
# With double dash '--version'

bash commandLine.sh --version=1.0 -rV
# With short options grouped together and long option
# With single dash '-version'

bash commandLine.sh -version=1.0 -rV

# OR with short option that takes value, value separated by whitespace
# by key

bash commandLine.sh -v 1.0 -rV

# OR with short option that takes value, value without whitespace
# separation from key.

bash commandLine.sh -v1.0 -rV

# OR Separating individual short options

bash commandLine.sh -v1.0 -r -V


getopt vs getopts .. дуже різні крос-платформи
shadowbq

35

Приклад, упакований getopt(мій дистрибутив /usr/share/getopt/getopt-parse.bash), виглядає так, що він охоплює всі ваші випадки:

#!/bin/bash

# A small example program for using the new getopt(1) program.
# This program will only work with bash(1)
# An similar program using the tcsh(1) script language can be found
# as parse.tcsh

# Example input and output (from the bash prompt):
# ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long "
# Option a
# Option c, no argument
# Option c, argument `more'
# Option b, argument ` very long '
# Remaining arguments:
# --> `par1'
# --> `another arg'
# --> `wow!*\?'

# Note that we use `"$@"' to let each command-line parameter expand to a 
# separate word. The quotes around `$@' are essential!
# We need TEMP as the `eval set --' would nuke the return value of getopt.
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
     -n 'example.bash' -- "$@"`

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
    case "$1" in
        -a|--a-long) echo "Option a" ; shift ;;
        -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
        -c|--c-long) 
            # c has an optional argument. As we are in quoted mode,
            # an empty parameter will be generated if its optional
            # argument is not found.
            case "$2" in
                "") echo "Option c, no argument"; shift 2 ;;
                *)  echo "Option c, argument \`$2'" ; shift 2 ;;
            esac ;;
        --) shift ; break ;;
        *) echo "Internal error!" ; exit 1 ;;
    esac
done
echo "Remaining arguments:"
for arg do echo '--> '"\`$arg'" ; done

11
Зовнішня команда getopt (1) ніколи не є безпечною для використання, якщо ви не знаєте, що це GNU getopt, ви викликаєте її специфічним для GNU способом, і ви гарантуєте, що GETOPT_COMPATIBLE не знаходиться в оточенні. Використовуйте замість getopts (оболонку вбудовану) або просто переведіть петлю на позиційні параметри.
Жилль Кінот

@sputnick, tyvm, цього не знав.
Брайан Каїн

14
Е, жодна зовнішня команда не є безпечною для використання за цим стандартом. У вбудованих getopts відсутні важливі функції, і якщо ви хочете перевірити наявність GETOPT_COMPATIBLE, це простіше, ніж перенесення функцій getopt.
Майкл Террі

12

Я знаю, що на це вже відповіли, але для запису і для тих, хто з тими ж вимогами, як і я, я вирішив опублікувати цю пов’язану відповідь. Код заповнений коментарями для пояснення коду.

Оновлена ​​відповідь:

Збережіть файл як getopt.sh:

#!/bin/bash

function get_variable_name_for_option {
    local OPT_DESC=${1}
    local OPTION=${2}
    local VAR=$(echo ${OPT_DESC} | sed -e "s/.*\[\?-${OPTION} \([A-Z_]\+\).*/\1/g" -e "s/.*\[\?-\(${OPTION}\).*/\1FLAG/g")

    if [[ "${VAR}" == "${1}" ]]; then
        echo ""
    else
        echo ${VAR}
    fi
}

function parse_options {
    local OPT_DESC=${1}
    local INPUT=$(get_input_for_getopts "${OPT_DESC}")

    shift
    while getopts ${INPUT} OPTION ${@};
    do
        [ ${OPTION} == "?" ] && usage
        VARNAME=$(get_variable_name_for_option "${OPT_DESC}" "${OPTION}")
            [ "${VARNAME}" != "" ] && eval "${VARNAME}=${OPTARG:-true}" # && printf "\t%s\n" "* Declaring ${VARNAME}=${!VARNAME} -- OPTIONS='$OPTION'"
    done

    check_for_required "${OPT_DESC}"

}

function check_for_required {
    local OPT_DESC=${1}
    local REQUIRED=$(get_required "${OPT_DESC}" | sed -e "s/\://g")
    while test -n "${REQUIRED}"; do
        OPTION=${REQUIRED:0:1}
        VARNAME=$(get_variable_name_for_option "${OPT_DESC}" "${OPTION}")
                [ -z "${!VARNAME}" ] && printf "ERROR: %s\n" "Option -${OPTION} must been set." && usage
        REQUIRED=${REQUIRED:1}
    done
}

function get_input_for_getopts {
    local OPT_DESC=${1}
    echo ${OPT_DESC} | sed -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/[][ -]//g"
}

function get_optional {
    local OPT_DESC=${1}
    echo ${OPT_DESC} | sed -e "s/[^[]*\(\[[^]]*\]\)[^[]*/\1/g" -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/[][ -]//g"
}

function get_required {
    local OPT_DESC=${1}
    echo ${OPT_DESC} | sed -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/\[[^[]*\]//g" -e "s/[][ -]//g"
}

function usage {
    printf "Usage:\n\t%s\n" "${0} ${OPT_DESC}"
    exit 10
}

Тоді ви можете використовувати його так:

#!/bin/bash
#
# [ and ] defines optional arguments
#

# location to getopts.sh file
source ./getopt.sh
USAGE="-u USER -d DATABASE -p PASS -s SID [ -a START_DATE_TIME ]"
parse_options "${USAGE}" ${@}

echo ${USER}
echo ${START_DATE_TIME}

Стара відповідь:

Нещодавно мені потрібно було використовувати загальний підхід. Я натрапив на таке рішення:

#!/bin/bash
# Option Description:
# -------------------
#
# Option description is based on getopts bash builtin. The description adds a variable name feature to be used
# on future checks for required or optional values.
# The option description adds "=>VARIABLE_NAME" string. Variable name should be UPPERCASE. Valid characters
# are [A-Z_]*.
#
# A option description example:
#   OPT_DESC="a:=>A_VARIABLE|b:=>B_VARIABLE|c=>C_VARIABLE"
#
# -a option will require a value (the colon means that) and should be saved in variable A_VARIABLE.
# "|" is used to separate options description.
# -b option rule applies the same as -a.
# -c option doesn't require a value (the colon absense means that) and its existence should be set in C_VARIABLE
#
#   ~$ echo get_options ${OPT_DESC}
#   a:b:c
#   ~$
#


# Required options 
REQUIRED_DESC="a:=>REQ_A_VAR_VALUE|B:=>REQ_B_VAR_VALUE|c=>REQ_C_VAR_FLAG"

# Optional options (duh)
OPTIONAL_DESC="P:=>OPT_P_VAR_VALUE|r=>OPT_R_VAR_FLAG"

function usage {
    IFS="|"
    printf "%s" ${0}
    for i in ${REQUIRED_DESC};
    do
        VARNAME=$(echo $i | sed -e "s/.*=>//g")
    printf " %s" "-${i:0:1} $VARNAME"
    done

    for i in ${OPTIONAL_DESC};
    do
        VARNAME=$(echo $i | sed -e "s/.*=>//g")
        printf " %s" "[-${i:0:1} $VARNAME]"
    done
    printf "\n"
    unset IFS
    exit
}

# Auxiliary function that returns options characters to be passed
# into 'getopts' from a option description.
# Arguments:
#   $1: The options description (SEE TOP)
#
# Example:
#   OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#   OPTIONS=$(get_options ${OPT_DESC})
#   echo "${OPTIONS}"
#
# Output:
#   "h:f:PW"
function get_options {
    echo ${1} | sed -e "s/\([a-zA-Z]\:\?\)=>[A-Z_]*|\?/\1/g"
}

# Auxiliary function that returns all variable names separated by '|'
# Arguments:
#       $1: The options description (SEE TOP)
#
# Example:
#       OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#       VARNAMES=$(get_values ${OPT_DESC})
#       echo "${VARNAMES}"
#
# Output:
#       "H_VAR|F_VAR|P_VAR|W_VAR"
function get_variables {
    echo ${1} | sed -e "s/[a-zA-Z]\:\?=>\([^|]*\)/\1/g"
}

# Auxiliary function that returns the variable name based on the
# option passed by.
# Arguments:
#   $1: The options description (SEE TOP)
#   $2: The option which the variable name wants to be retrieved
#
# Example:
#   OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#   H_VAR=$(get_variable_name ${OPT_DESC} "h")
#   echo "${H_VAR}"
#
# Output:
#   "H_VAR"
function get_variable_name {
    VAR=$(echo ${1} | sed -e "s/.*${2}\:\?=>\([^|]*\).*/\1/g")
    if [[ ${VAR} == ${1} ]]; then
        echo ""
    else
        echo ${VAR}
    fi
}

# Gets the required options from the required description
REQUIRED=$(get_options ${REQUIRED_DESC})

# Gets the optional options (duh) from the optional description
OPTIONAL=$(get_options ${OPTIONAL_DESC})

# or... $(get_options "${OPTIONAL_DESC}|${REQUIRED_DESC}")

# The colon at starts instructs getopts to remain silent
while getopts ":${REQUIRED}${OPTIONAL}" OPTION
do
    [[ ${OPTION} == ":" ]] && usage
    VAR=$(get_variable_name "${REQUIRED_DESC}|${OPTIONAL_DESC}" ${OPTION})
    [[ -n ${VAR} ]] && eval "$VAR=${OPTARG}"
done

shift $(($OPTIND - 1))

# Checks for required options. Report an error and exits if
# required options are missing.

# Using function version ...
VARS=$(get_variables ${REQUIRED_DESC})
IFS="|"
for VARNAME in $VARS;
do
    [[ -v ${VARNAME} ]] || usage
done
unset IFS

# ... or using IFS Version (no function)
OLDIFS=${IFS}
IFS="|"
for i in ${REQUIRED_DESC};
do
    VARNAME=$(echo $i | sed -e "s/.*=>//g")
    [[ -v ${VARNAME} ]] || usage
    printf "%s %s %s\n" "-${i:0:1}" "${!VARNAME:=present}" "${VARNAME}"
done
IFS=${OLDIFS}

Я не перевіряв це грубо, тому у мене могли бути якісь помилки.


1
Якщо ви використовуєте getoptsфункцію, додайте local OPTIND OPTARGдо функції
glenn jackman

@glennjackman насправді це скоріше скоріше, ніж сед-підхід, ніж використанняgetopts
Себастьян

8

Приклад POSIX 7

Також варто перевірити приклад із стандарту: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html

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" "$*"

І тоді ми можемо спробувати це:

$ sh a.sh
Remaining arguments are: 
$ sh a.sh -a
Option -a specified
Remaining arguments are: 
$ sh a.sh -b
No arg for -b option
Usage: a.sh: [-a] [-b value] args
$ sh a.sh -b myval
Option -b "myval" specified
Remaining arguments are: 
$ sh a.sh -a -b myval
Option -a specified
Option -b "myval" specified
Remaining arguments are: 
$ sh a.sh remain
Remaining arguments are: remain
$ sh a.sh -- -a remain
Remaining arguments are: -a remain

Випробуваний в Ubuntu 17.10, shтире 0,5.8.


0

"getops" і "getopt" дуже обмежені. Хоча "getopt" пропонується не використовувати взагалі, він пропонує довгі варіанти. Якщо "getopts" дозволяє лише параметри одного символу, такі як "-a" "-b". Є ще кілька недоліків при використанні будь-якого.

Тому я написав невеликий сценарій, який замінює "getopts" та "getopt". Це початок, його, можливо, можна було б значно покращити.

Оновлення 08-04-2020 : Я додав підтримку дефісів, наприклад, "- ім'я упаковки".

Використання: "./script.sh install install --package" name with space "--build --archive"

# Example:
# parseArguments "${@}"
# echo "${ARG_0}" -> package
# echo "${ARG_1}" -> install
# echo "${ARG_PACKAGE}" -> "name with space"
# echo "${ARG_BUILD}" -> 1 (true)
# echo "${ARG_ARCHIVE}" -> 1 (true)
function parseArguments() {
  PREVIOUS_ITEM=''
  COUNT=0
  for CURRENT_ITEM in "${@}"
  do
    if [[ ${CURRENT_ITEM} == "--"* ]]; then
      printf -v "ARG_$(formatArgument "${CURRENT_ITEM}")" "%s" "1" # could set this to empty string and check with [ -z "${ARG_ITEM-x}" ] if it's set, but empty.
    else
      if [[ $PREVIOUS_ITEM == "--"* ]]; then
        printf -v "ARG_$(formatArgument "${PREVIOUS_ITEM}")" "%s" "${CURRENT_ITEM}"
      else
        printf -v "ARG_${COUNT}" "%s" "${CURRENT_ITEM}"
      fi
    fi

    PREVIOUS_ITEM="${CURRENT_ITEM}"
    (( COUNT++ ))
  done
}

# Format argument.
function formatArgument() {
  ARGUMENT="${1^^}" # Capitalize.
  ARGUMENT="${ARGUMENT/--/}" # Remove "--".
  ARGUMENT="${ARGUMENT//-/_}" # Replace "-" with "_".
  echo "${ARGUMENT}"
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.