Bash'de "set -o isim seti" kullanılırken bir değişkenin ayarlanıp ayarlanmadığını test edin


100

Aşağıdaki kod, ilişkisiz bir değişken hatasıyla çıkar. Hala set -oisim seti seçeneğini kullanırken bunu nasıl düzeltebilirim ?

#!/bin/bash

set -o nounset

if [ ! -z ${WHATEVER} ];
 then echo "yo"
fi

echo "whatever"

Yanıtlar:


101
#!/bin/bash

set -o nounset


VALUE=${WHATEVER:-}

if [ ! -z ${VALUE} ];
 then echo "yo"
fi

echo "whatever"

Bu durumda, ayarlanmamışsa VALUEboş bir dize olur WHATEVER. "Parametre Genişletme" altında {parameter:-word}bakabileceğiniz genişletmeyi kullanıyoruz man bash.


15
sadece if [! -z {VALUE}] ABD doları; if [! -z $ {WHATEVER: -}];
Angelom

18
:-değişkenin ayarlanmamış veya boş olup olmadığını kontrol eder . Eğer kontrol etmek isterseniz sadece o tanımsız olsun, kullanın -: VALUE=${WHATEVER-}. Ayrıca, bir değişkenin boş olup olmadığını kontrol etmenin daha okunaklı bir yolu:if [ "${WHATEVER+defined}" = defined ]; then echo defined; else echo undefined; fi
l0b0

1
Ayrıca, $WHATEVERyalnızca boşluk içeriyorsa bu işe yaramaz - Cevabıma bakın.
l0b0

11
! -zSadece " -n" yerine " " kullanmanın bir nedeni var mı ?
Jonathan Hartley

32

Beklediğiniz sonucu elde etmek istiyorsanız değişkenleri alıntı yapmanız gerekir:

check() {
    if [ -n "${WHATEVER-}" ]
    then
        echo 'not empty'
    elif [ "${WHATEVER+defined}" = defined ]
    then
        echo 'empty but defined'
    else
        echo 'unset'
    fi
}

Ölçek:

$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER='   '
$ check
not empty

Göre haricinde ben bu denedim ve bu eserler şaşırdım ... Her şey doğrudur "info bash", "${WHATEVER-}"bir olması gereken ":"önce (iki nokta üst üste) "-": gibi (tire) "${WHATEVER:-}"ve "${WHATEVER+defined}"daha önce iki nokta üst üste sahip olmalıdır "+"(artı) gibi: "${WHATEVER:+defined}". Benim için, iki nokta üst üste olsun veya olmasın her iki şekilde de çalışır. 'Nix'in bazı sürümlerinde, büyük olasılıkla iki nokta üst üste eklemeden çalışmayacaktır, bu nedenle muhtemelen eklenmelidir.
Kevin Fegan

9
Hayır, -, +, :+, ve :-tüm desteklenmektedir. Eski değişken olup olmadığını tespit ayarlanır ve ikinci bu olup olmadığını tespit set ya da boş . Kimden man bash: "İki nokta üst üste işaretinin çıkarılması, yalnızca ayarlanmamış bir parametre için bir teste neden olur."
l0b0

1
Nevermind =). Haklısın. Bunu nasıl kaçırdım bilmiyorum.
Kevin Fegan

Gönderen docs : kolon dahil olup olmadığını, her iki parametrenin varlığının ve onun değeri boş olmadığını operatör testleri Başka bir deyişle; iki nokta üst üste belirtilmezse, operatör yalnızca var olup olmadığını test eder.
Acumenus

11

Bir oneliner'e ne dersiniz?

[ -z "${VAR:-}" ] && echo "VAR is not set or is empty" || echo "VAR is set to $VAR"

-z hem boş hem de ayarlanmamış değişken için kontrol eder


2
Hayır, -zyalnızca sonraki parametrenin boş olup olmadığını kontrol eder. -zsadece [komutun bir argümanıdır . Değişken genişleme bir şey yapmadan önce gerçekleşir [ -z.
dolmen

1
Bu doğru çözüm gibi görünüyor, çünkü $ VAR ayarlanmadıysa bir hata oluşturmaz. @dolmen ne zaman işe yaramayacağına dair bir örnek verebilir misiniz?
Chris Stryczynski

@dolmen, param genişlemesi hakkında çeşitli bash kaynaklarını okuduktan ve diğer cevapları aşırı karmaşık bulduktan sonra, bunda yanlış bir şey görmüyorum. bu nedenle, teknik olarak doğru olsa da, "netleştirmeniz", ayarlanmayan ile boşu ayırt etmeniz gerekmedikçe pratikte oldukça anlamsız görünür. Ayarlanmamış, boş ve boş olmayan (bash 4) test ettim ve hemen hemen her seferinde reklamı yapılanı yaptı.
JL Peyret

10

Varsayımlar:

$ echo $SHELL
/bin/bash
$ /bin/bash --version | head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
$ set -o nounset

Etkileşimli olmayan bir komut dosyasının bir hata yazdırmasını ve bir değişken boşsa veya ayarlanmamışsa çıkmasını istiyorsanız:

$ [[ "${HOME:?}" ]]

$ [[ "${IAMUNBOUND:?}" ]]
bash: IAMUNBOUND: parameter null or not set

$ IAMNULL=""
$ [[ "${IAMNULL:?}" ]]
bash: IAMNULL: parameter null or not set

Komut dosyasının çıkmasını istemiyorsanız:

$ [[ "${HOME:-}" ]] || echo "Parameter null or not set."

$ [[ "${IAMUNBOUND:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

$ IAMNULL=""
$ [[ "${IAMUNNULL:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.

Hatta kullanabilir [ve ]yerine [[ve]] üstünü kullanabilirsiniz, ancak ikincisi Bash'de tercih edilir.

Kolonun yukarıda ne yaptığına dikkat edin. Gönderen docs :

Başka bir deyişle, kolon dahil edilmişse, operatör hem parametrenin varlığını hem de değerinin boş olmadığını test eder; iki nokta üst üste belirtilmezse, operatör yalnızca var olup olmadığını test eder.

Görünüşe göre -nya da gerek yok -z.

Özetle, genellikle sadece kullanabilirim [[ "${VAR:?}" ]]. Örneklere göre, bu bir hata yazdırır ve bir değişken boşsa veya ayarlanmamışsa çıkar.


4

Kullanabilirsiniz

if [[ ${WHATEVER:+$WHATEVER} ]]; then

fakat

if [[ "${WHATEVER:+isset}" == "isset" ]]; then

daha okunaklı olabilir.


Dize karşılaştırmaları , taşınabilirliğe yardımcı olmak için =değil ==ve mümkünse [bunun yerine standart (POSIX) operatörünü kullanmalıdır [[.
Jens

2
@Jens Soru bash'a özeldir ve bash'a özgü olanları içerir set -o nounset. #!/bin/bashBetiğinizin üstüne bir koyarsanız , aslında en iyisi bash'ın geliştirmelerini kullanmaktır.
Bruno Bronosky

0

Bu tam olarak yukarıda istenen kullanım durumu olmasa da , kullanmak istiyorsanız nounset(veya-u ) varsayılan davranışın istediğiniz davranış olduğunu : açıklayıcı bir mesajla sıfırdan farklı çıkmak.

Çözüm olarak yayınlamaya değer olduğunu düşündüğümü fark etmem yeterince uzun sürdü.

İstediğiniz tek şey çıkarken başka bir şeyi yankılamaksa veya biraz temizlik yapmaksa, bir tuzak kullanabilirsiniz.

:-Operatör aksi istediğini olasılıkla gerçek değildir.

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.