Bir bash betiğine parametrelerden birinin bir dizeyle eşleşip eşleşmediğini kontrol edin


67

Bir bash betiğine iletilen parametrelerin bir dizgeyle eşleşip eşleşmediğini kontrol etmek istediğim bir komut dosyası yazmaya çalışıyorum. Şu an onu kurma yöntemim

if [ "$3" != "-disCopperBld" -a "$4" != "-disCopperBld" -a "$5" != "-disCopperBld" -a "$6" != "-disCopperBld"]

ama çok sayıda parametre olabilir, bu yüzden bunu yapmanın daha iyi bir yolu olup olmadığını merak ediyordum?

Teşekkürler

EDIT: Bu kod yığınını denedim ve betiği -disableVenusBld seçeneğiyle çağırdım, ancak yine de "Build build" komutunu yazdırıyor. Yanlış bir şey mi yapıyorum? Şimdiden teşekkürler!

while [ $# -ne 0 ]
do
    arg="$1"
    case "$arg" in
        -disableVenusBld)
            disableVenusBld=true
            ;;
        -disableCopperBld)
            disableCopperBld=true
            ;;
        -disableTest)
            disableTest=true
            ;;
        -disableUpdate)
            disableUpdate=true
            ;;
        *)
            nothing="true"
            ;;
    esac
    shift
done

if [ "$disableVenusBld" != true ]; then
    echo "Starting build"
fi

Cevaplarınız için teşekkürler, bana yardım etmek için zaman ayırdığınız için teşekkür ederim. Bir kod kodu denedim ama neyin yanlış gittiğini çözemiyorum. Herhangi bir fikir? (Kodu, orijinal yayınımın düzenlemesine yapıştırdım)
iman453

Hmm: benim için çalışıyor. Buraya eklediklerinizin #! /bin/sh -üstüne ekledim , betiği çalıştırılabilir hale getirdim, sonra ./t.sh"Başlatılıyor" yazıyor ancak ./t.sh -disableVenusBldhiçbir şey yazdırmıyor.
Norman Gray

Yanıtlar:


59

Bir kabuk komut dosyasında seçenek işlemesi yapıyorsunuz gibi görünüyor. İşte bunun için deyim:

#! /bin/sh -

# idiomatic parameter and option handling in sh
while test $# -gt 0
do
    case "$1" in
        --opt1) echo "option 1"
            ;;
        --opt2) echo "option 2"
            ;;
        --*) echo "bad option $1"
            ;;
        *) echo "argument $1"
            ;;
    esac
    shift
done

exit 0

(Girintiyi ;;belirtmek için birkaç kural vardır ve bazı kabuklar (--opt1)ayraç eşleşmesine yardımcı olmak için seçenekleri belirtmenize izin verir , ancak bu temel fikirdir)


3
Bir shiftkomutun argüman sayısı önceden bilinmediğinde, örneğin kullanıcılar istedikleri kadar argüman verebildiklerinde bir ifade kullanılır. Bu gibi durumlarda, argümanlar whilebir test koşulu olan bir döngüde işlenir $#. Argüman sayısı sıfırdan büyük olduğu sürece bu koşul geçerlidir. $1Değişken ve shiftbildiride, sürecin her argüman. Her defasında shiftçalıştırılan argüman sayısı azaltılır ve sonunda whiledöngünün çıktığı sıfır olur . kaynak
Serge Stroobandt


26

Bu benim için çalıştı. Tam olarak istediğinizi yapar ve başka bir şey yapmaz (seçenek işlemesi yoktur). Bunun iyi ya da kötü olması poster için bir alıştırmadır :)

if [[ "$*" == *YOURSTRING* ]]
then
    echo "YES"
else
    echo "NO"
fi

Bu, $* süper test [[]]braketlerinin özel kullanımı ve bash özelliklerinden yararlanır .


2
IMHO bunun için en doğru cevap olmalıydı çünkü soru sadece bir parametrenin varlığını kontrol etmeyi gerektiriyordu. Ben değişen Ancak düzenledikten $*için $@test edilecek dize bu konuda bash belgelerine boşluk ve katma bağlantıya sahip olabileceğinden,.
saat 07

9
= ~ İşlecini kullanmak mı istediniz? Aksi halde, bunun neden işe yaraması gerektiğini anlamıyorum ve tam olarak betiği denediğimde gerçekten işe yaramıyor.
Seppo Enarvi

3
Çalışmıyor. bash -c 'echo args=$*; [[ "$@" == "bar" ]] && echo YES || echo NO' -- foo bar
Tobia,

2
Bu, tüm argüman listesini ile karşılaştırır your string. Bence bu cevabın önerdiği şeyi yapmalısın . yani: bash -c 'echo args=$*; for i in "$@" ; do [[ $i == "bar" ]] && echo "Is set!" && break ; done' -- bar fooişe yarar.
starfry

2
Bu cevap son dört yıldır yanlıştı çünkü h7r'in düzenlemesi bozdu. Orijinal cevabı (şimdi geri yükledi), "senin dizenin" glob karakterleri içermemesi ve bazı yanlış pozitifler olması koşuluyla çalışır. Örneğin, komut create a new certificateve "dizgeniz" ise cat, certificate içerdiği için bir eşleşme bildirilecektir cat.
Scott,

8

Tüm parametre alanını (joker karakterlerle) aramaya ne dersiniz:

if [[ $@ == *'-disableVenusBld'* ]]
then

Düzenleme: Tamam, tamam, bu popüler bir cevap değildi. Peki ya bu, mükemmel!

if [[ "${@#-disableVenusBld}" = "$@" ]]
then
    echo "Did not find disableVenusBld"
else
    echo "Found disableVenusBld"
fi

Edit2: Tamam, tamam, belki de bu mükemmel değil ... Sadece -param listenin başındaysa ve -paramXZY veya -paramABC ile de eşleşirse işe yarar. Hala orjinal problemin bash string manipülasyonuyla çok güzel bir şekilde çözülebileceğini düşünüyorum, ama burada tam olarak çözmedim ... -Sen ??


İkinci öneriniz - filtreleme ikamesini tam ikame ile karşılaştırmak - oldukça iyi sonuç veriyor ve argümanlar listesini bozmama avantajına sahip.
Donal Fellows

İkinci önerinin (özellikle ${@#) ne yaptığını açıklayabilir misiniz ?
geliştirmem

1
@velop Tabii! Yani $@tüm komut satırı argümanlarını tutan özel bir değişken olduğunu biliyorsunuz ? Ben sadece "-disableVenusBld" alt dizgisini kaldırmak için bu değişkende Bash string manipülasyonunu kullandım ve sonra orijinaliyle karşılaştırdım $@. Öyleyse $@, -foo -baro ${@#-disableVenusBld}zaman hala eşittir -foo -bar, bu yüzden aradığım bayrağın mevcut olmadığını görebiliyorum. Ancak, $@eşit -foo -disableVenusBld -barardından ${@#-disableVenusBld}olurdu -foo -bareşit olmadığı $@böylece aradığım bayrak bulunduğunu söylüyor! Güzel ha!
Zengin

Burada Bash dize manipülasyon hakkında daha fazla bilgi @velop: tldp.org/LDP/abs/html/string-manipulation.html
Rich

@Rich oldukça temiz ^^, açıklama için teşekkürler.
geliştirmem

4
disCopperBld=
for x; do
  if [ "$x" = "-disCopperBld" ]; then disCopperBld=1; break; fi
done
if [ -n "$disCopperBld" ]; then
  ...
fi

Yalnızca başlayan parametreleri test etmeniz gerekirse $3, arama işlevinde yapın:

## Usage: search_trailing_parameters NEEDLE NUM "$@"
## Search NEEDLE amongst the parameters, skipping $1 through ${$NUM}.
search_trailing_parameters () {
  needle=$1
  shift $(($2 + 2))
  for x; do
    if [ "$x" = "$needle" ]; then return 0; fi
  done
  return 1
}
if search_trailing_parameters -disCopperBld 2 "$@"; then
  ...
fi

Ama bunu neden en başta yapmaya çalıştığınızı merak ediyorum, bu ortak bir ihtiyaç değil. Genellikle, Dennis'in önceki sorunuza cevabında olduğu gibi seçenekleri sırayla işlerdiniz .

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.