Bash kabuk betiğinde giriş bağımsız değişkeninin varlığını kontrol etme


1337

Bir giriş argümanının varlığını kontrol etmem gerekiyor. Aşağıdaki komut dosyasına sahibim

if [ "$1" -gt "-1" ]
  then echo hi
fi

alırım

[: : integer expression expected

Var olup olmadığını görmek için ilk önce giriş argümanını1 nasıl kontrol edebilirim?

Yanıtlar:


2328

Bu:

if [ $# -eq 0 ]
  then
    echo "No arguments supplied"
fi

$#Değişken size komut geçirildi giriş argümanların sayısını söyleyecektir.

Veya bir bağımsız değişkenin boş bir dize olup olmadığını kontrol edebilirsiniz:

if [ -z "$1" ]
  then
    echo "No argument supplied"
fi

-z"$ 1" genişleme boş dize olup olmadığını anahtarı test edecek. Boş bir dize ise, gövde yürütülür.


62
Bunu bu şekilde, kısa sözdiziminde ve yine POSIX kabul edilebilir şekilde yapmayı seviyorum. [ -z "$1" ] && echo "No argument supplied" Benim için daha kolay oldukları için tek astarları tercih ederim; çıkış değerinin kontrol edilmesi de kullanıma kıyasla daha hızlıif
JM Becker

168
Büyük olasılıkla exit 1, betiğin çalışması için bağımsız değişken gerektiğinde if bloğunun içine echos'unuzun sonuna bir eklemek istersiniz . Açık, ama bütünlük için kayda değer.
msanford

16
İlk argümanın başlatılması ancak boş olması nadiren faydalı olsa da mümkündür; programname "" secondarg third. $#Onay açıkça ifade sayısını kontrol eder.
Üçlü

39
Bir noob için, özellikle komut dosyası olmayan bir arka plandan gelen biri için, bu şeyler hakkında bazı özelliklerden bahsetmek de önemlidir. Ayrıca, açılış ve kapanış ayracı sonrasında bir alana ihtiyacımız olduğunu da söylemiş olabilirsiniz. Aksi takdirde işler işe yaramaz. Ben kendimi bir script noob (C arka plan geliyor) ve zor yolunu buldum. Sadece tüm şeyleri "olduğu gibi" kopyalamaya karar verdiğimde işler benim için işe yaradı. O zaman açılış desteğinden sonra ve kapanıştan önce bir boşluk bırakmak zorunda olduğumu fark ettim.
HighOnMeat

72
ve isteğe bağlı argümanlar içinif [ ! -z "$1" ]; then ...
gcb

346

Bu şekilde göstermek daha iyidir

if [[ $# -eq 0 ]] ; then
    echo 'some message'
    exit 1
fi

Çok az sayıda argümanınız varsa, normal olarak çıkış yapmanız gerekir.


72
Hayır değil: bu exit 1genellikle istediğiniz bir [[ ]]şeydir ve (iirc) genellikle daha makul olan testi kullanır . Yani insanlar körü körüne kopya yapıştırma kodu için bu daha iyi bir yanıttır.
dshepherd

42
[] Ve [[]] arasındaki fark hakkında daha fazla bilgi için bkz. Stackoverflow.com/questions/3427872/…
Sebastián Grignoli

104

Bazı durumlarda, kullanıcının betiğe bir argüman iletip iletmediğini kontrol etmeniz ve yoksa varsayılan bir değere düşmeniz gerekir. Aşağıdaki senaryoda olduğu gibi:

scale=${2:-1}
emulator @$1 -scale $scale

Burada kullanıcı scale2. parametre olarak geçmediyse, -scale 1varsayılan olarak Android emülatörünü başlatırım . ${varname:-word}bir genişletme operatörüdür. Başka genişletme operatörleri de var:

  • ${varname:=word}hangi ayarlar tanımsız varnamedönen yerine worddeğerini;
  • ${varname:?message}varnametanımlanmış ve boş değilse döndürür veya messagekomut dosyasını yazdırır ve iptal eder (ilk örnek gibi);
  • ${varname:+word}wordyalnızca varnametanımlanmış ve boş değilse geri döner ; aksi takdirde null değerini döndürür.

1
Yukarıdaki örnek kullanılıyor gibi görünüyor ${varname?message}. Ekstra :bir yazım hatası mı yoksa davranışı değiştiriyor mu?
Eki

6
Eki, ":" yerleşik bir komut ve bu örnekte / bin / true için kısayol. Temel olarak, sağlanan bağımsız değişkenleri yok sayan bir yap-yok komutunu temsil eder. Tercümanın "$ varname" (kesinlikle olmasını istemediğiniz) içeriğini yürütmeye çalışmasını önlemek için bu testte gereklidir. Ayrıca kayda değer; bu yöntemle istediğiniz sayıda değişkeni test edebilirsiniz. Ve hepsi belirli hata mesajlarıyla. ie: ${1?"First argument is null"} ${2?"Please provide more than 1 argument"}
user.friendly

48

Deneyin:

 #!/bin/bash
 if [ "$#" -eq  "0" ]
   then
     echo "No arguments supplied"
 else
     echo "Hello world"
 fi

4
Neden $#ve için çift tırnaklara ihtiyacınız var 0?
user13107

1
$ # Ve 0 gibi çift tırnak olmadan kullanırsak sorun değil
Ranjithkumar T

pencerelerde, mingw bu gitmek için tek yoldur.
Lajos Meszaros

2
Bu cevap az önce yaptığım bir senaryo için harika bir başlangıç ​​noktası sağlar. Gösterdiğiniz için teşekkürler else.
Chris K

2
@ user13107 bash içindeki çift tırnaklı değişkenler globbing'i (örn. dosya adlarını genişletmek gibi foo*) ve kelime bölmeyi (yani değer boşluk içeriyorsa içeriği bölmeyi) önler . Bu durumda alıntı $#yapmak gerekli değildir çünkü her iki durum da geçerli değildir. Alıntı 0yapmak da gerekli değildir, ancak bazı insanlar gerçekten ipler oldukları ve daha açık hale getirdikleri için değerleri alıntılamayı tercih ederler.
Dennis

39

Betiğe argüman iletilip iletilmediğini tespit etmenin başka bir yolu:

((!$#)) && echo No arguments supplied!

(( expr ))İfadenin Kabuk Aritmetiği kurallarına göre değerlendirilmesine neden olduğunu unutmayın .

Herhangi bir argümanın yokluğunda çıkmak için şöyle diyebiliriz:

((!$#)) && echo No arguments supplied! && exit 1

Yukarıdakileri söylemenin başka bir (benzer) yolu:

let $# || echo No arguments supplied

let $# || { echo No arguments supplied; exit 1; }  # Exit if no arguments!

help let diyor:

let: let arg [arg ...]

  Evaluate arithmetic expressions.

  ...

  Exit Status:
  If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.

2
-1 bu, bir argümanın varlığını doğrularsa en kötü yöntem olabilir .. artı tarih değişikliğini tetikleyebilir ve potansiyel olarak kötü şeyler yapabilir.
user.friendly

2
bunun yerine exitzsh sürecimi öldürür, onu returnöldürmez kullanırım
Timo

Neden ((!$#))tarih değişikliğini tetiklesin ki?
Zhro

25

Bu snippet'i genellikle basit komut dosyaları için kullanırım:

#!/bin/bash

if [ -z "$1" ]; then
    echo -e "\nPlease call '$0 <argument>' to run this command!\n"
    exit 1
fi

1
Yani, bu sadece bir argümana ihtiyacınız var mı?
Danijel

21

Sadece işaret etmek için daha temel bir nokta olduğundan, dizenizin boş olduğunu test edebileceğinizi ekleyeceğim:

if [ "$1" ]; then
  echo yes
else
  echo no
fi

Aynı şekilde, arg sayısını bekliyorsanız sonuncunuzu test edin:

if [ "$3" ]; then
  echo has args correct or not
else
  echo fixme
fi

ve benzeri herhangi bir arg veya var


4

Bağımsız değişkenin var olup olmadığını kontrol etmek isterseniz, bağımsız değişkenlerin # sayısının hedef bağımsız değişken numaranıza eşit veya daha büyük olup olmadığını kontrol edebilirsiniz.

Aşağıdaki komut dosyası bunun nasıl çalıştığını gösterir

test.sh

#!/usr/bin/env bash

if [ $# -ge 3 ]
then
  echo script has at least 3 arguments
fi

aşağıdaki çıktıyı üretir

$ ./test.sh
~
$ ./test.sh 1
~
$ ./test.sh 1 2
~
$ ./test.sh 1 2 3
script has at least 3 arguments
$ ./test.sh 1 2 3 4
script has at least 3 arguments

3

Küçük bir hatırlatma olarak, Bash sayısal testi operatörleri sadece tamsayılar üzerinde çalışmak ( -eq, -lt, -gevs.)

$ Var'ımın ints olduğundan emin olmak istiyorum

var=$(( var + 0 ))

Onları test etmeden önce, sadece "[: integer arg gerekli” hatasına karşı savunmak için.


1
Düzenli hile, ancak lütfen unutmayın: bash'ın aritmetik şamandıraları işleyememesi nedeniyle, bu yöntem bir sözdizimi hatasına neden olabilir ve sıfır olmayan bir dönüşe neden olabilir, bu da errexit'in etkinleştirildiği bir engel olacaktır. var=$(printf "%.0f" "$var")şamandıraları işleyebilir, ancak bir dize verildiğinde sıfır olmayan çıkıştan muzdariptir. Bir awk sakıncası yoksa, bu yöntem ben kullanımının bir tamsayı uygulanmasından en sağlam gibi görünüyor: var=$(<<<"$var" awk '{printf "%.0f", $0}'). Var ayarlanmamışsa, varsayılan olarak "0" dır. Var bir kayan nokta ise, en yakın tamsayıya yuvarlanır. Negatif değerler de kullanılabilir.
user.friendly

0

bir astar bash işlevi doğrulaması

myFunction() {

    : ${1?"forgot to supply an argument"}
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}

işlev adı ve kullanımı ekle

myFunction() {

    : ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage:  ${FUNCNAME[0]} some_integer"}
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

}

tamsayı olup olmadığını kontrol etmek için doğrulama ekle

ek doğrulama eklemek için (örneğin, iletilen bağımsız değişkenin bir tam sayı olup olmadığını kontrol etmek için), bir doğrulama işlevini çağırmak için doğrulama işlemini bir astarda değiştirin:

: ${1?"forgot to supply an argument ${FUNCNAME[0]}() Usage:  ${FUNCNAME[0]} some_integer"} && validateIntegers $1 || die "Must supply an integer!"

sonra, argümanı doğrulayan ve başarıda 0, hatada 1 ve hatada komut dosyasını iptal eden bir die işlevi döndüren bir doğrulama işlevi oluşturun

validateIntegers() {

    if ! [[ "$1" =~ ^[0-9]+$ ]]; then
        return 1 # failure
    fi
    return 0 #success

}

die() { echo "$*" 1>&2 ; exit 1; }

Daha da basit - sadece kullanın set -u

set -u atıfta bulunulan her değişkenin kullanıldığında ayarlandığından emin olun, bu yüzden ayarlayın ve unutun

myFunction() {
    set -u
    if [ "$1" -gt "-1" ]; then
        echo hi
    fi

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