Getopt'u bash komut satırında sadece uzun seçeneklerle nasıl kullanabilirim?


13

getoptBash komut satırında bir komut var . getoptkısa seçeneklerle (örneğin getopt -o axby "$@") kullanılabilir ve hem kısa hem de uzun seçeneklerle (örneğin getopt -o axby -l long-key -- "$@") kullanılabilir, ancak şimdi sadece uzun seçeneklere ihtiyacım var (yani kısa seçenekler hiç yok), ancak komut getopt -l long-key -- "$@"yok --long-keyseçeneği ayrıştırın . Peki getoptkomutu sadece uzun seçeneklerle nasıl kullanabilirim ? Yoksa imkansız mı yoksa sadece emrin bir hatası getoptmı?


Dahili için etiketliyorsunuz getopts, ancak /usr/bin/getoptkomutu kullanıyorsunuz .
Anthon

@Anthon Üzgünüm, yanlış etiketi kullandım, ancak 300 üne ihtiyaç duyan başka bir etiket eklemek için yeterli üne sahip değilim. Ancak, şu anda yanlış etiketi sildim.
Victor

Yanıtlar:


15

getopthiçbir kısa seçenek ile mükemmel para cezası. Ancak kısa seçenekleriniz olmadığını söylemelisiniz. Sözdiziminde bir tuhaflık - kılavuzdan:

İlk bölümde hiç -oveya --optionsseçenek bulunmazsa, ikinci parçanın ilk parametresi kısa seçenekler dizesi olarak kullanılır.

Testinizde olan budur: seçenekler listesi ve tek argüman olarak getopt -l long-key -- --long-key foodavranır . kullanım--long-key-egklnoyfoo

getopt -o '' -l long-key -- "$@"

Örneğin

$ getopt -l long-key -o '' -- --long-key foo
 --long-key -- 'foo'
$ getopt -l long-key -o '' -- --long-key --not-recognized -n foo
getopt: unrecognized option '--not-recognized'
getopt: invalid option -- 'n'
 --long-key -- 'foo'

OP'ın karıştırılmasını mü getoptsve getoptcevabınıza Infect? Sen yorumlama ile başlayan getoptsyalnızca söz sonra getopt.
Anthon

@Anthon Tüm cevabım, sorunun getoptne olduğu GNU coreutils'in programıyla ilgili. Bunu söyleyen metni düzelttim getopts. Teşekkürler. getoptsuzun seçenekler bile yapmaz, bu yüzden bunların hiçbiri geçerli değildir getopts.
Gilles 'SO- kötü olmayı bırak'

OP aslen getoptsetikete sahipti . Cevabınızı değiştirmek istemedim, çünkü normalde hakkında yazdıklarınızı benden çok daha iyi biliyorsunuz :-)
Anthon

Bunu anlamaya çalışırken neredeyse bir saatimi kaybettim. Bana birkaç boş kahve yudumladın. Teşekkürler ... şimdi bu kahveyi daha iyi kullanalım. ☕️
dmmd

1

Hakkında bilgi yok getoptama getoptsyerleşik sadece bu gibi uzun seçenekleri işlemek için kullanılabilir:

while getopts :-: o
do  case "$o$OPTARG" in
(-longopt1) process ;;
(-longopt2) process ;;
esac; done

Tabii ki, uzun seçeneklerin argümanları olması gerekiyorsa, bu işe yaramaz. Yine de yapılabilir, ama bunun üzerinde çalışmayı öğrendiğim gibi. Başlangıçta buraya dahil ederken, uzun seçenekler için çok fazla faydası olmadığını fark ettim. Bu durumda, case (match)alanlarımı yalnızca tek, öngörülebilir bir karakterle kısaltıyordum . Şimdi, bildiğim, kısa seçenekler için mükemmel olması - bilinmeyen uzunlukta bir dize üzerinde döngü ve seçenek dizesine göre tek bayt seçerken en kullanışlıdır. Seçenek Ama olan Argo, bir ile yapıyoruz bir şey yok for var do case $var ino yapabileceğini kombinasyonu. Bence basit tutmak daha iyi.

Aynı şeyin doğru olduğundan şüpheleniyorum getoptama kesin olarak söyleyecek kadar bilgim yok. Ben takdir geldiniz Erişi / atama ilişki öncelikle bağlıdır - Aşağıdaki arg dizisi göz önüne alındığında, kendi küçük arg ayrıştırıcı gösterecek aliasve $((shell=math)).

set -- this is ignored by default --lopt1 -s 'some '\'' 
args' here --ignored   and these are ignored \
--alsoignored andthis --lopt2 'and 

some "`more' --lopt1 and just a few more

Birlikte çalışacağım arg dizesi bu. Şimdi:

aopts() { env - sh -s -- "$@"
} <<OPTCASE 3<<\OPTSCRIPT
acase() case "\$a" in $(fmt='
        (%s) f=%s; aset "?$(($f)):";;\n'
        for a do case "$a" in (--) break;;
        (--*[!_[:alnum:]]*) continue;;
        (--*) printf "$fmt" "$a" "${a#--}";;
        esac;done;printf "$fmt" '--*' ignored)
        (*) aset "" "\$a";;esac
shift "$((SHIFT$$))"; f=ignored; exec <&3 
OPTCASE
aset()  {  alias "$f=$(($f${1:-=$(($f))+}1))"
        [ -n "${2+?}" ] && alias "${f}_$(($f))=$2"; }
for a do acase; done; alias
#END
OPTSCRIPT

Bu, arg dizisini --ayırıcıyla ayrılmış bir veya iki bağımsız değişken kümesi vermenize bağlı olarak iki farklı yoldan biriyle işler . Her iki durumda da, arg dizisinin işleme dizileri için geçerlidir.

Eğer şöyle çağırırsanız:

: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"

İlk iş emri, acase()işlevini aşağıdaki gibi görünecek şekilde yazmak olacaktır :

acase() case "$a" in 
    (--lopt1) f=lopt1; aset "?$(($f)):";;
    (--lopt2) f=lopt2; aset "?$(($f)):";;
    (--*) f=ignored; aset "?$(($f)):";;
    (*) aset "" "$a";;esac

Ve yanında shift 3. acase()İşlev tanımındaki komut ikamesi , çağıran kabuk işlevin giriş belgelerini oluşturduğunda değerlendirilir, ancak acase()çağıran kabukta hiçbir zaman çağrılmaz veya tanımlanmaz. Tabii ki alt kabukta çağrılır ve böylece bu şekilde komut satırında ilgili seçenekleri dinamik olarak belirtebilirsiniz.

Sınırlandırılmamış bir dizi verirseniz acase(), dize ile başlayan tüm bağımsız değişkenler için eşleşmelerle doldurulur --.

İşlev neredeyse tüm işlemlerini alt kabukta yapar - bağımsız değişkenin değerlerinin her birini ilişkilendirilebilir adlarla atanan takma adlara yinelemeli olarak kaydeder. Bu işlem sırasında, kaydedilen tüm değerleri yazdırır alias- bu, alıntılanan tüm kaydedilmiş değerleri, değerleri kabuğa yeniden girebilecek şekilde yazdırmak için POSIX tarafından belirtilir. Öyleyse yaptığım zaman ...

aopts --lopt1 --lopt2 -- "$@"

Çıkışı şöyle görünür:

...ignored...
lopt1='8'
lopt1_1='-s'
lopt1_2='some '\'' args'
lopt1_3='here'
lopt1_4='and'
lopt1_5='just'
lopt1_6='a'
lopt1_7='few'
lopt1_8='more'
lopt2='1'
lopt2_1='and

some "`more'

Arg listesinden geçerken bir eşleşme için vaka bloğunu denetler. Orada bir eşleşme bulursa bayrak atar f=optname. Bir kez daha geçerli bir seçenek buluncaya kadar, sonraki her argümanı geçerli bayrağa göre oluşturduğu bir diziye ekler. Aynı seçenek birden çok kez belirtilirse, sonuç bileşiği geçersiz kılmayın. Durumda olmayan her şey - ya da yoksayılan seçenekleri izleyen herhangi bir bağımsız değişken - yok sayılan bir diziye atanır .

Çıkış, kabuk tarafından otomatik olarak kabuk girişi için kabuk korumalıdır ve bu nedenle:

eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")"

... tamamen güvenli olmalı. Herhangi bir nedenle güvenli değilse , büyük olasılıkla kabuk koruyucunuza bir hata raporu göndermelisiniz.

Her eşleşme için iki tür diğer ad değeri atar. İlk olarak, bir bayrak ayarlar - bu, bir seçeneğin eşleşmeyen bağımsız değişkenlerden önce gelip gelmediği olur. Böylece --flagarg listesindeki herhangi bir olay tetiklenir flag=1. Bu bileşik değil - --flag --flag --flagsadece alır flag=1. Ancak bu değer , onu izleyebilecek tüm argümanlar için artar. Bir dizin anahtarı olarak kullanılabilir. evalYukarıdakileri yaptıktan sonra yapabilirim:

printf %s\\n "$lopt1" "$lopt2"

...almak...

8
1

Ve bu yüzden:

for o in lopt1 lopt2
do list= i=0; echo "$o = $(($o))"
        while [ "$((i=$i+1))" -le "$(($o))" ]
        do list="$list $o $i \"\${${o}_$i}\" "
done; eval "printf '%s[%02d] = %s\n' $list";  done

ÇIKTI

lopt1 = 8
lopt1[01] = -s
lopt1[02] = some ' args
lopt1[03] = here
lopt1[04] = and
lopt1[05] = just
lopt1[06] = a
lopt1[07] = few
lopt1[08] = more
lopt2 = 1
lopt2[01] = and

some "`more

Ve uymayan argümanlar almak için yukarıdaki alanda yok sayılır yerine for ... in:

ignored = 10
ignored[01] = this
ignored[02] = is
ignored[03] = ignored
ignored[04] = by
ignored[05] = default
ignored[06] = and
ignored[07] = these
ignored[08] = are
ignored[09] = ignored
ignored[10] = andthis
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.