Kabuk betiğindeki anahtarları nasıl işleyebilirim?


17

Bağımsız değişkenleri tanıyacak -xve --xxxxanahtar olarak tanıyacak bazı yerleşik araçlar var mı , yoksa tüm giriş değişkenlerini gözden geçirmek, tire testi yapmak ve daha sonra bağımsız değişkenleri ayrıştırmak zorunda mısınız?

Yanıtlar:


16

Kullanın getopts.

POSIX özelliklerinde olduğu gibi oldukça taşınabilir. Maalesef uzun seçenekleri desteklemiyor.

Ayrıca bu bak getopts öğretici wiki bash-hacker nezaket ve bu soruyu stackoverflow dan.

Yalnızca kısa seçeneklere ihtiyacınız varsa getopts(sessiz olmayan hata bildirimi kullanarak) için tipik kullanım şekli :

# 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
Kullanmadan getoptönce her zaman GNU getopt olarak doğrulanması gerektiği belirtilmelidir , ancak yine de getoptsdaha taşınabilir (ve genellikle daha güzel) olduğu gibi kullanmamalısınız . Eğer varsa yapmak nedense aramak gereğini, bir GNU özgü bir şekilde diyoruz ve emin GETOPT_COMPATIBLEortamda değil.
Chris Down

İki nokta üst üste ne yapıyor while getopts "ab:" opt?
user394

1
@ user394 :Bir seçenek mektubundan sonra, bir argüman gerektirdiğini belirtir. :İlk karakter olarak A , hata mesajlarını bastırmak anlamına gelir.
jw013

22

Sanırım bash ya da benzerini kullanıyorsun. Bir örnek:

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
+=Dizi ile kullanmak için +1 . Bunu yapabileceğini bilmiyordum. Güzel!
James Sneeringer

5

Parametreleri ayrıştırmak için bir döngü yazmanız gerekir. Gerçekten de getoptskolayca yapmak için komutu kullanabilirsiniz .

Bu, getoptsmanuel sayfadan basit bir örnektir :

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

Geçenlerde çok yönlü ve herhangi bir sırada birden fazla anahtar türü için izin verilen iş için bir senaryo yazdım. Tam senaryoyu bariz yasal nedenlerle açıklayamıyorum (şu anda yanımda olmadığını söylemiyorum), ama işte et .. bir alt rutine koyabilir ve sonunda çağırabilirsiniz betiğinizin:

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

Ben bash betiğinizi 400 satır / 15k karakterden daha azıyla sınırlandırmanızı öneririm; bahsettiğim senaryom bu boyutu aştı ve üzerinde çalışılması oldukça zorlaştı. Görev için çok daha uygun olan Perl'de yeniden yazmaya başladım. Betikte senaryolarınız üzerinde çalışırken bunu aklınızda bulundurun. Bash küçük scriptler ve onelinerler için harikadır, ancak daha karmaşık bir şeydir ve Perl'de yazmanız daha iyi olur.

Not, yukarıdakileri test etmedim, bu yüzden muhtemelen işe yaramaz, ancak genel fikri ondan alırsınız.


optionsSonunda arama şekliniz doğru değil, geri dönecektir -bash: syntax error near unexpected token $@. Olarak adlandırın options "$@".
Chris Down

Evet, Perl ve Bash'ı karıştırdım. Düzeltildi.
laebshade

Bunun yerine bu whilekoşul olmamalı (($#))mı?
manatwork

Neden iki parantez setine ihtiyacınız var $#? Düzenleme: haklısın. Sabitwhile (( "$#" ))
laebshade
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.