Getopların bash'da nasıl kullanılacağına bir örnek


345

myscriptDosyayı şu şekilde aramak istiyorum :

$ ./myscript -s 45 -p any_string

veya

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

Gereksinimlerim:

  • getopt girdi argümanlarını almak için
  • -sbir hata döndürmezseniz , var olup olmadığını kontrol edin
  • 'den sonraki değerin -s45 veya 90 olduğunu kontrol edin
  • -pvar olup olmadığını kontrol edin ve
  • kullanıcı girerse ./myscript -hveya yalnızca ./myscriptyardımı görüntülerse

Şimdiye kadar bu kodu denedim:

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

Ama bu kodla hatalar alıyorum. Bash ve nasıl yapılır getopt?


2
Seçeneklerin isteğe bağlı olması gerekir. Eğer tarafından belirtilen değeri gerektiriyorsa -s, bunu bir pozisyon argüman olun: ./myscript 45 anystring.
chepner

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

Mesele yok -pbir seçenek (o mevcut değilse olduğunu, programınız devam edebilirsiniz) aslında. Bu durumda ./myscript 45 -p any_string,. (Bunun getoptkarışık seçenekler ve konumsal argümanları işleyebileceğini düşünüyorum , oysa bashyerleşik komut getoptstüm konumsal argümanların seçeneklerden sonra yerleştirilmesini gerektiriyor.)
Chepner

Yanıtlar:


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}"

Örnek çalıştırmalar:

$ ./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 çağrısında, neden önde gelen bir kolon var? "H" ne zaman sonra iki nokta üst üste alır?
e40

7
Should usage()gerçekten return 1?
Pithikos

6
@Pithikos İyi bir nokta. Sağduyu, -honun aracılığıyla çağrıldığında 0, var olmayan bir bayrağa çarptıktan sonra geri dönmesi gerektiğini söyler >0(basitlik için bu durumlar arasında ayrım yapmadım ve kimse sizi ikinci durumda kullanım metnini yazdırmaya zorlamaz) . != 0Yine de her zaman geri dönen programlar gördüm -h/--help. Belki de insanların bunu kaynak plakası olarak kullanmaları durumunda snippet'i güncellemeliyim (umarım hayır)?
Adrian Frühwirth

1
@ A.Danischewski Bu ( getopts') tasarım gereği, "isteğe bağlı argümanlar" diye bir şey yoktur getopts. Ayrıştırıcı, bir sonraki belirtecin geçerli seçenek için bir bağımsız değişken olup olmadığını veya kendi başına bir seçenek olup olmadığını bilmiyor çünkü -phedeflenen değer olabilir. Sen olabilir kesinlikle bir seçenek parametresi başka bir geçerli seçenek, evet gibi görünmüyor biliyorum eğer bu sorunu kesmek, ama bir isteğe bağlı bağımsız değişkenler POSIX'deki tanımlanmamış bir sebebi var diyebiliriz.
Adrian Frühwirth

4
@ user1011471 Haklısın! Kıvırcık parantezler, tabiri caizse, sadece bashdeğişkenleri tanımlamak için lexer'a yardım edin . Birçok durumda gereksizdirler ve her zaman bunları kullandığım gerçeği sadece kişisel kodlama stili meselesidir. Bana göre, belirsizliğe ilişkin ayrıştırma kurallarını hatırlamak yerine bunları her zaman kullanmak daha kolay (ve daha güzel). C tarzı bir dilde (estetik ve / veya aptalca hatalardan kaçınmak) if (foo) { bar; }bunun yerine neden yazılması neredeyse aynı if (foo) bar;.
Adrian Frühwirth

109

Orijinal kod ile ilgili sorun:

  • h:değiştirilmemesi gereken parametreyi bekler, bu yüzden sadece h(iki nokta üst üste olmadan) olarak değiştirin
  • beklemek için argüman listesine -p any_stringeklemeniz gerekirp:

Temel olarak :seçenek anlamına gelir sonra argüman gerektirir.


Temel sözdizimi getopts(bakınız :) man bash:

getopts OPTSTRING VARNAME [ARGS...]

nerede:

  • OPTSTRING beklenen bağımsız değişkenlerin listesini içeren dizedir,

    • h- seçenek için onay -h olmadan parametreleri; desteklenmeyen seçeneklerde hata verir;
    • h:- parametre -h ile seçeneği kontrol edin ; desteklenmeyen seçeneklerde hata verir;
    • abc- seçeneklerin onay -a, -b, -c; desteklenmeyen seçeneklerde hata verir ;
    • :abc- seçeneklerin onay -a, -b, -c; desteklenmeyen seçeneklerde hataları susturur ;

      Notlar: Başka bir deyişle, seçeneklerin önünde iki nokta üst üste kodunuzdaki hataları ele almanızı sağlar. Değişken ?, desteklenmeyen seçenek :durumunda, eksik değer olması durumunda içerecektir .

  • OPTARG - geçerli bağımsız değişken değerine ayarlanmışsa,

  • OPTERR - Bash'in hata mesajlarını gösterip göstermeyeceğini gösterir.

Kod şu şekilde olabilir:

#!/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

Örnek kullanım:

$ ./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

Bkz: Küçük getopts öğretici Bash Hackerlar Wiki


2
Buna kullanım fonksiyonu değiştirin: usage() { echo "$0 usage:" && grep "[[:space:]].)\ #" $0 | sed 's/#//' | sed -r 's/([a-z])\)/-\1/'; exit 0; }. Harf seçeneğinden önce yalnızca tek bir boşluk karakteri oluşturur, # öğesini yorumdan kaldırır ve harf seçeneğinden önce '-' komutunu daha net hale getirir.
poagester

2
@kenorb: Seçeneklerin önündeki iki nokta, desteklenmeyen seçenekleri yok saymaz, ancak bash hatalarını susturur ve kodunuzda işlemenizi sağlar. Değişken '?' desteklenmeyen seçenek olması durumunda ve ':' eksik değer olması durumunda.
Hynek -Pichi- Vychodil

1
Ayrıntılı dokümanlar için teşekkürler, :bu notları görene kadar doğru alamadım . :Bir argüman beklediğimiz seçeneklere bir eklememiz gerekiyor .
Aukhan

51

kullanım getopt

Neden getopt?

Karışıklığı önlemek ve ayrıştırdığımız seçenekleri açıklığa kavuşturmak için ayrıntılı komut satırı argümanlarını ayrıştırmak, böylece komutların okuyucusunun neler olduğunu anlayabilmesi.

Getopt nedir?

getoptkabuk yordamlarıyla kolay ayrıştırma için komut satırlarındaki seçenekleri ayırmak (ayrıştırmak) ve yasal seçenekleri denetlemek için kullanılır. Bunu getopt(3)yapmak için GNU rutinlerini kullanır .

getopt aşağıdaki seçenek türlerine sahip olabilir.

  1. Değersiz seçenekler
  2. anahtar / değer çifti seçenekleri

Not: Bu belgede sözdizimini açıklarken:

  • [] İçindeki herhangi bir şey sözdiziminde / örneklerde isteğe bağlı bir parametredir.
  • yer tutucudur, yani gerçek bir değerle değiştirilmelidir.

NASIL KULLANILIR getopt?

Sözdizimi: İlk Form

getopt optstring parameters

Örnekler:

# 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"

Burada h, v, t seçenekler ve -h -v -t seçenekler komut satırında nasıl verilmelidir.

  1. 'h' değeri olmayan bir seçenektir.
  2. 'v:', -v seçeneğinin değere sahip olduğunu ve zorunlu bir seçenek olduğunu belirtir. ':', bir değere sahip olduğu anlamına gelir.
  3. 't ::', -t seçeneğinin değere sahip olduğunu ancak isteğe bağlı olduğunu gösterir. '::' isteğe bağlı anlamına gelir.

İsteğe bağlı parametrede, değerin seçenekle boşluk ayırması olamaz. Yani, "-t123" örneğinde -t seçeneği 123 değerdir.

Sözdizimi: İkinci Form

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

Burada getopt beş parçaya ayrıldıktan sonra

  • Komutun kendisi yani getopt
  • Getopt_options, bağımsız değişkenlerin nasıl ayrıştırılacağını açıklar. tek çizgi uzun seçenekleri, çift çizgi seçenekleri.
  • -, getopt_options öğesini ayrıştırmak istediğiniz seçeneklerden ve izin verilen kısa seçeneklerden ayırır
  • Kısa seçenekler - bulunduktan hemen sonra alınır. Form ilk sözdizimi gibi.
  • Parametreler, bunlar programa geçtiğiniz seçeneklerdir. Ayrıştırmak ve ayarlanan gerçek değerleri almak istediğiniz seçenekler.

Örnekler

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

Sözdizimi: Üçüncü Form

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

Burada getopt beş parçaya ayrıldıktan sonra

  • Komutun kendisi yani getopt
  • Getopt_options, bağımsız değişkenlerin nasıl ayrıştırılacağını açıklar. tek çizgi uzun seçenekleri, çift çizgi seçenekleri.
  • Kısa seçenekler yani -o veya --options. Form ilk sözdiziminde olduğu gibi "-o" seçeneğinde ve "-" (çift tire) öncesi.
  • -, getopt_options öğesini ayrıştırmak istediğiniz seçeneklerden ve izin verilen kısa seçeneklerden ayırır
  • Parametreler, bunlar programa geçtiğiniz seçeneklerdir. Ayrıştırmak ve ayarlanan gerçek değerleri almak istediğiniz seçenekler.

Örnekler

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

GETOPT_OPTIONS

getopt_options komut satırı parametrelerini ayrıştırma şeklini değiştirir.

Aşağıda getopt_options bazı

Seçenek: -l veya --longoptions

Getopt komutu, çok karakterli seçeneklerin tanınmasına izin vermelidir. Birden çok seçenek virgülle ayrılır.

Örneğin, --name=Karthikkomut satırında gönderilen uzun bir seçenektir. Getopt'ta uzun seçeneklerin kullanımı

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

Name: belirtildiğinden, seçenek bir değer içermelidir

Seçenek: -a veya --alternatif

Getopt komutu, uzun seçeneğin çift tire '-' yerine tek bir tire '-' olmasına izin vermelidir.

Örnek olarak, --name=Karthiksadece-name=Karthik

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

Kodla birlikte eksiksiz bir komut dosyası örneği:

#!/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

Bu komut dosyasını çalıştırma:

# 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 .. çok farklı platformlar arası uyum
shadowbq

35

getopt(Dağıtımımın içine koydum /usr/share/getopt/getopt-parse.bash) ile paketlenmiş örnek , tüm durumlarınızı kapsıyor gibi görünüyor:

#!/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
Harici komut getopt (1), GNU getopt olduğunu bilmediğiniz sürece , onu GNU'ya özgü bir şekilde çağırırsınız ve GETOPT_COMPATIBLE'ın ortamda olmadığından emin olursunuz. Bunun yerine getopts (shell builtin) kullanın ya da sadece konumsal parametreler üzerinde döngü yapın.
Gilles Quenot

@sputnick, tyvm, bunu bilmiyordum.
Brian Cain

14
Eh, bu standart tarafından harici komutların kullanılması güvenli değildir. Dahili getopts önemli özellikleri eksik ve eğer GETOPT_COMPATIBLE kontrol etmek istiyorsanız bu getopt özelliklerini taşımak daha kolay.
Michael Terry

12

Bunun zaten cevaplandığını biliyorum, ancak kayıt ve benimle aynı gereksinimleri olan herkes için bu ilgili cevabı göndermeye karar verdim. Kod, açıklamak için yorumlarla doludur.

Güncel cevap:

Dosyayı şu şekilde kaydedin 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
}

O zaman bu şekilde kullanabilirsiniz:

#!/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}

Eski cevap:

Son zamanlarda genel bir yaklaşım kullanmam gerekiyordu. Bu çözümle karşılaştım:

#!/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}

Bunu kabaca test etmedim, bu yüzden orada bazı hatalar olabilir.


1
Eğer kullanıyorsanız getoptsbir işlevde, eklemek local OPTIND OPTARGişlevine
Glenn jackman

@glennjackman aslında kullanmaktan çok bir sed yaklaşımı gibigetopts
Sebastian

8

POSIX 7 örneği

Ayrıca, standarttan örneği kontrol etmeye değer: 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" "$*"

Ve sonra deneyebiliriz:

$ 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 sh17.10'da test edilmiştir , çizgi 0.5.8'dir.


0

"getops" ve "getopt" çok sınırlıdır. "Getopt" un hiç kullanılmaması önerilse de, uzun seçenekler sunar. Burada "getopts" sadece "-a" "-b" gibi tek karakter seçeneklerine izin verir. Bunlardan birini kullanırken birkaç dezavantaj daha vardır.

Yani "getopts" ve "getopt" yerine küçük bir komut dosyası yazdım. Bu bir başlangıç, muhtemelen çok geliştirilebilir.

Güncelleme 08-04-2020 : "--package-name" gibi kısa çizgiler için destek ekledim.

Kullanımı: "./script.sh paket install --package" alan adı "--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}"
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.