Bash betiğine geçirilen bağımsız değişken sayısını kontrol edin


731

Gerekli bağımsız değişken sayısı karşılanmadıysa, Bash komut dosyamın bir hata iletisi yazdırmasını istiyorum.

Aşağıdaki kodu denedim:

#!/bin/bash
echo Script name: $0
echo $# arguments 
if [$# -ne 1]; 
    then echo "illegal number of parameters"
fi

Bilinmeyen bir nedenden dolayı aşağıdaki hatayı aldım:

test: line 4: [2: command not found

Neyi yanlış yapıyorum?


54
Senaryonuza isim vermemelisiniz test. Bu standart bir Unix komutunun adıdır, gölgelendirmek istemezsiniz.
Barmar

20
Her boşluk kullanımı çevresinde '[' ( '[[') ya da '(' ( '((') ise bash bildirimler.
zoska

5
@Zoska yorumuna eklemek için, önce [[komut olarak uygulandığından] bir boşluk kullanmanız gerekir.
Daniel Da Cunha

1
aşağıdaki bağlantıda daha iyi bir örnek verilmiştir: stackoverflow.com/questions/4341630/…
ramkrishna

3
@ Barmar kesinlikle testPATH üzerinde olmadığı sürece iyi isimlendirme ?
user253751

Yanıtlar:


1105

Tıpkı diğer basit komutlar gibi [ ... ]veya testargümanları arasında boşluk olmasını gerektirir.

if [ "$#" -ne 1 ]; then
    echo "Illegal number of parameters"
fi

Veya

if test "$#" -ne 1; then
    echo "Illegal number of parameters"
fi

Öneriler

Bash içindeyken, [[ ]]sözcük bölme ve yol adı genişletme işlemlerini değişkenlerine yapmadığı için kullanmayı tercih edin, bir ifadenin parçası olmadığı sürece tırnak işareti gerekli olmayabilir.

[[ $# -ne 1 ]]

Ayrıca, sıralanmamış koşul gruplaması, desen eşleştirme (ile genişletilmiş desen eşleme extglob) ve normal ifade eşleştirme gibi başka özelliklere de sahiptir .

Aşağıdaki örnek, bağımsız değişkenlerin geçerli olup olmadığını kontrol eder. Bir veya iki argümana izin verir.

[[ ($# -eq 1 || ($# -eq 2 && $2 == <glob pattern>)) && $1 =~ <regex pattern> ]]

Saf aritmetik ifadeler için kullanan (( ))bazı hala daha iyi olabilir, ancak bunlar hala mümkündür [[ ]]mi onun aritmetik operatörleri ile -eq, -ne, -lt, -le, -gt, veya -getek bir dize bağımsız değişken olarak ifade yerleştirerek:

A=1
[[ 'A + 1' -eq 2 ]] && echo true  ## Prints true.

Bunu diğer özelliklerle de birleştirmeniz gerekiyorsa faydalı olacaktır [[ ]].

Komut dosyasından çıkma

Geçersiz parametreler iletildiğinde komut dosyasının çıkış yapması da mantıklıdır. Bu zaten ekangas tarafından yorumlarda önerildi, ancak birisi bu değeri döndürülen değer olarak sahip olmak için düzenledi , bu yüzden de doğru yapabilirim.-1

-1Bash tarafından bir argüman olarak kabul edilmesine rağmen exit, açıkça belgelenmemiştir ve ortak bir öneri olarak kullanılma hakkı yoktur. 64o tanımlanan beri en biçimsel değeri de olduğu sysexits.hile #define EX_USAGE 64 /* command line usage error */. Çoğu araçları sever lsde geri 2geçersiz argümanlar üzerinde. 2Senaryolarımı da döndürürdüm ama son zamanlarda artık gerçekten umursamıyorum ve sadece 1tüm hatalarda kullanıyordum. Ancak, 2en yaygın ve muhtemelen OS'ye özgü olmadığı için buraya yerleştirelim .

if [[ $# -ne 1 ]]; then
    echo "Illegal number of parameters"
    exit 2
fi

Referanslar


2
OP: Bunun [başka bir komut olduğunu aklınızdan çıkarmayın, yani deneyin which [.
Aslan

5
@Leo Komutları oluşturulabilir ve oluşturulamaz. Bash, [bir yerleşik, [[bir anahtar kelime. Bazı eski kabuklarda [bile yerleşik değildir. Komutları gibi [birçok sistemde harici komut olarak doğal arada var, ancak iç komutlar ile baypas sürece kabuk tarafından önceliklidir commandveya exec. Kabuğun nasıl değerlendirdiklerine dair belgelerine bakın. Farklılıklarını ve her kabukta nasıl farklı davranabileceklerini not edin.
konsolebox

79

Rakamlarla ilgileniyorsanız aritmetik ifadeleri kullanmak iyi bir fikir olabilir .

if (( $# != 1 )); then
    echo "Illegal number of parameters"
fi

Mevcut davada bu neden iyi bir fikir olabilir? Verimlilik, taşınabilirlik ve diğer konular göz önüne alındığında, en basit ve en evrensel olarak anlaşılan sözdizimini kullanmak en iyisi değil [ ... ]mi?
Maksimum

@Max aritmetik genişletmeleri $(( ))süslü değildir ve tüm POSIX mermileri tarafından uygulanmalıdır. Ancak, (( ))sözdizimi (onsuz $) bunun bir parçası değildir. Herhangi bir nedenle sınırlıysanız, [ ]bunun yerine mutlaka kullanabilirsiniz , ancak o zaman [[ ]]da kullanmamanız gerektiğini unutmayın . Umarım [ ]bu özelliklerin tuzaklarını ve nedenlerini anlarsın . Ancak bu bir Bash sorusuydu, bu yüzden Bash cevapları veriyoruz ( “Genel bir kural olarak, [[dizeler ve dosyalar için kullanılır. Sayıları karşılaştırmak istiyorsanız, bir ArithmeticExpression kullanın” ).
Aleks-Daniel Jakimenko-A.

40

[] :! =, =, == ... üzerinde dize karşılaştırma işleçleri, -eq, -gt ... ise aritmetik ikili olanlar.

Kullanmak istiyorum:

if [ "$#" != "1" ]; then

Veya:

if [ $# -eq 1 ]; then

9
==Bir belgesiz özelliği, aslında olur GNU ile çalışmak test. Ayrıca olur FreeBSD ile işe testama olabilir çalışmaz foo test . Sadece standart karşılaştırmadır =(sadece Bilginize).
Martin Tournoij

1
Bash man girişinde belgelenmiştir: == ve! = Operatörleri kullanıldığında, operatörün sağındaki dize bir desen olarak kabul edilir ve aşağıda Desen Eşleştirme altında açıklanan kurallara göre eşleştirilir. Kabuk seçeneği nocasematch etkinleştirilirse, eşleme alfabetik karakterlerin durumuna bakılmaksızın gerçekleştirilir. Dize örüntüyle eşleşirse (==) veya eşleşmiyorsa (! =) Dönüş değeri 0, aksi takdirde 1 olur. Desenin herhangi bir kısmı, onu bir dize olarak eşleşmeye zorlamak için alıntılanabilir.
jhvaras

2
@jhvaras: Bu: O Carpetsmoker dedi aynen böyle olabilir bazı uygulamalarda çalışır (ve gerçekten de Bash çalışır) ancak o POSIX uyumlu değil . Örneğin, olacaktır başarısız olan dash: dash -c '[ 1 == 1 ]'. POSIX yalnızca belirtir =, belirtmez ==.
gniourf_gniourf

34

Yalnızca belirli bir argüman eksikse kefaletle ilgileniyorsanız, Parametre Değiştirme mükemmeldir:

#!/bin/bash
# usage-message.sh

: ${1?"Usage: $0 ARGUMENT"}
#  Script exits here if command-line parameter absent,
#+ with following error message.
#    usage-message.sh: 1: Usage: usage-message.sh ARGUMENT

bashisms yüklü değil mi?
Dwight Spencer

@DwightSpencer Önemli mi?
konsolebox

@Temak Belirli sorularınız varsa yapabilirim, ancak bağlantılı makale benden daha iyi açıklıyor.
Pat

13

Çalışan basit bir astar aşağıdakileri kullanarak yapılabilir:

[ "$#" -ne 1 ] && ( usage && exit 1 ) || main

Bu, aşağıdakilere ayrılır:

  1. bash değişkenini $ # değerine eşit olmayan parametrelerin boyutu için test edin 1 (alt komut sayımız)
  2. true ise, use () işlevini çağırın ve durumla çıkın 1
  3. else main () işlevini çağırır

Dikkat edilmesi gerekenler:

  • usage () basit yankı olabilir "$ 0: params"
  • main uzun bir senaryo olabilir

1
Bu satırdan sonra başka bir satır kümeniz varsa, bu yanlış olur çünkü exit 1yalnızca alt kabuğun bağlamı için geçerli olur ( usage; false ). Seçenek ayrıştırma söz konusu olduğunda bu basitleştirmenin hayranı değilim, ama { usage && exit 1; }bunun yerine kullanabilirsiniz . Ya da muhtemelen sadece { usage; exit 1; }.
konsolebox

1
@konsolebox (kullanım && çıkış 1) ksh, zsh ve bash için bash 2.0'a geri döner. {...} sözdizimi yalnızca 4.0+ bash sürümüne yakındır. Eğer bir yol sizin için iyi çalışıyorsa beni yanlış anlamayın, o zaman kullanın ama herkes yaptığınız aynı bash uygulamasını kullanmaz ve bashisms değil standartları posix için kodlamalıyız.
Dwight Spencer

Ne dediğinden emin değilim. {...}ortak bir sözdizimidir ve shPOSIX standartlarına uymayan eski mermiler de dahil olmak üzere tüm mermiler olmasa bile çoğunun kullanımına açıktır .
konsolebox

7

Bu bash hile sayfasına göz atın, çok yardımcı olabilir.

Aktarılan argümanların uzunluğunu kontrol etmek için şunu kullanırsınız: "$#"

Aktarılan argüman dizisini kullanmak için "$@"

Uzunluğu kontrol etme ve yineleme örneği:

myFunc() {
  if [[ "$#" -gt 0 ]]; then
    for arg in "$@"; do
      echo $arg
    done
  fi
}

myFunc "$@"

Bu eklem bana yardımcı oldu, ancak benim ve durumum için birkaç şey eksikti. Umarım bu birine yardımcı olur.


0

Güvenli tarafta olmak istemeniz durumunda, getopts kullanmanızı tavsiye ederim.

İşte küçük bir örnek:

    while getopts "x:c" opt; do
      case $opt in
        c)
          echo "-$opt was triggered, deploy to ci account" >&2
          DEPLOY_CI_ACCT="true"
          ;;
            x)
              echo "-$opt was triggered, Parameter: $OPTARG" >&2 
              CMD_TO_EXEC=${OPTARG}
              ;;
            \?)
              echo "Invalid option: -$OPTARG" >&2 
              Usage
              exit 1
              ;;
            :)
              echo "Option -$OPTARG requires an argument." >&2 
              Usage
              exit 1
              ;;
          esac
        done

daha fazla ayrıntıya bakın, örneğin http://wiki.bash-hackers.org/howto/getopts_tutorial


0

Burada sadece bir parametrenin verilip verilmediğini kontrol etmek için basit bir astarlar aksi takdirde komut dosyasından çıkın:

[ "$#" -ne 1 ] && echo "USAGE $0 <PARAMETER>" && exit

-1

Test koşulu arasına boşluklar eklemelisiniz:

if [ $# -ne 1 ]; 
    then echo "illegal number of parameters"
fi

Umarım bu yardımcı olur.

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.