Bash'de sıfır olmayan uzunluklu dize için test yapın: [-n “$ var”] veya [“$ var”]


182

Bash komut dosyalarının iki farklı yolla sıfır olmayan bir uzunluk dizesi için test ettiğini gördüm. Çoğu komut dosyası -nseçeneği kullanır :

#!/bin/bash
# With the -n option
if [ -n "$var" ]; then
  # Do something when var is non-zero length
fi

Ancak -n seçeneği gerçekten gerekli değildir:

# Without the -n option
if [ "$var" ]; then
  # Do something when var is non-zero length
fi

Hangisi daha iyi bir yol?

Benzer şekilde, sıfır uzunluk için test etmenin daha iyi yolu:

if [ -z "$var" ]; then
  # Do something when var is zero-length
fi

veya

if [ ! "$var" ]; then
  # Do something when var is zero-length
fi

Yanıtlar:


394

Düzenleme: Bu [(aka test) ve arasında daha fazla fark gösteren daha eksiksiz bir sürümüdür [[.

Aşağıdaki tabloda, bir değişkenin alıntılanıp alıntılanmayacağı, tek veya çift parantez kullanıp kullanmadığınız ve değişkenin yalnızca boşluk içerip içermediği, bir değişkenin test edilip edilmediğinin -n/-zbir değişkenin kontrol edilmesi için uygun olup olmadığını etkileyen şeyler olduğunu göstermektedir.

     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b
     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"
-----+------------------------------------+------------------------------------
unset| false false true  false true  true | false false false false true  true
null | false false true  false true  true | false false false false true  true
space| false true  true  true  true  false| true  true  true  true  false false
zero | true  true  true  true  false false| true  true  true  true  false false
digit| true  true  true  true  false false| true  true  true  true  false false
char | true  true  true  true  false false| true  true  true  true  false false
hyphn| true  true  true  true  false false| true  true  true  true  false false
two  | -err- true  -err- true  -err- false| true  true  true  true  false false
part | -err- true  -err- true  -err- false| true  true  true  true  false false
Tstr | true  true  -err- true  -err- false| true  true  true  true  false false
Fsym | false true  -err- true  -err- false| true  true  true  true  false false
T=   | true  true  -err- true  -err- false| true  true  true  true  false false
F=   | false true  -err- true  -err- false| true  true  true  true  false false
T!=  | true  true  -err- true  -err- false| true  true  true  true  false false
F!=  | false true  -err- true  -err- false| true  true  true  true  false false
Teq  | true  true  -err- true  -err- false| true  true  true  true  false false
Feq  | false true  -err- true  -err- false| true  true  true  true  false false
Tne  | true  true  -err- true  -err- false| true  true  true  true  false false
Fne  | false true  -err- true  -err- false| true  true  true  true  false false

Bir değişkenin sıfır olmayan bir uzunluk olup olmadığını bilmek istiyorsanız, aşağıdakilerden birini yapın:

  • değişkeni tek parantez içinde alıntılayın (sütun 2a)
  • -ndeğişkeni tek parantez içinde kullanın ve alıntılayın (sütun 4a)
  • tırnaklı veya tırnaksız veya tırnaksız çift parantez kullanın -n(sütun 1b - 4b)

Sütun la'da "iki" etiketli satırdan başlayarak sonucun değişkenin içeriğini koşullu ifadenin bir parçasıymış gibi [değerlendirdiğini belirten uyarı (sonuç, "T" veya "F" açıklama sütunu). Tüm (sütun 1 b) kullanıldığında, değişken içermektedir bir dizi olarak görülmektedir ve değerlendirilmez.[[

Sütunlar 3a ve 5a'daki hatalar, değişken değerinin bir boşluk içerdiği ve değişkenin tırnaksız olmasından kaynaklanır. Yine, 3b ve 5b sütunlarında gösterildiği gibi [[, değişkenin içeriğini bir dize olarak değerlendirir.

Buna uygun olarak, sıfır uzunluklu dizeler için testlerde, sütun 6a, 5b ve 6b bunu yapmanın doğru yollarını gösterir. Ayrıca, olumsuzlama, ters işlemi kullanmaktan daha açık bir niyet gösteriyorsa, bu testlerden herhangi birinin reddedilebileceğini unutmayın. Örneğin: if ! [[ -n $var ]].

Kullanıyorsanız [, beklenmedik sonuçlar almadığınızdan emin olmanın anahtarı değişkeni tırnak içine almaktır. Kullanmak [[önemli değil.

Gizlenmekte olan hata iletileri "tekli operatör bekleniyor" veya "ikili operatör bekleniyor" şeklindedir.

Bu, yukarıdaki tabloyu oluşturan komut dosyasıdır.

#!/bin/bash
# by Dennis Williamson
# 2010-10-06, revised 2010-11-10
# for http://stackoverflow.com/q/3869072
# designed to fit an 80 character terminal

dw=5    # description column width
w=6     # table column width

t () { printf '%-*s' "$w" " true"; }
f () { [[ $? == 1 ]] && printf '%-*s' "$w" " false" || printf '%-*s' "$w" " -err-"; }

o=/dev/null

echo '     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b'
echo '     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"'
echo '-----+------------------------------------+------------------------------------'

while read -r d t
do
    printf '%-*s|' "$dw" "$d"

    case $d in
        unset) unset t  ;;
        space) t=' '    ;;
    esac

    [ $t ]        2>$o  && t || f
    [ "$t" ]            && t || f
    [ -n $t ]     2>$o  && t || f
    [ -n "$t" ]         && t || f
    [ -z $t ]     2>$o  && t || f
    [ -z "$t" ]         && t || f
    echo -n "|"
    [[ $t ]]            && t || f
    [[ "$t" ]]          && t || f
    [[ -n $t ]]         && t || f
    [[ -n "$t" ]]       && t || f
    [[ -z $t ]]         && t || f
    [[ -z "$t" ]]       && t || f
    echo

done <<'EOF'
unset
null
space
zero    0
digit   1
char    c
hyphn   -z
two     a b
part    a -a
Tstr    -n a
Fsym    -h .
T=      1 = 1
F=      1 = 2
T!=     1 != 2
F!=     1 != 1
Teq     1 -eq 1
Feq     1 -eq 2
Tne     1 -ne 2
Fne     1 -ne 1
EOF

1
Teşekkürler! Ben "tek parantez (sütun 2a) değişken teklif" IMO tarzını benimsemeye karar verdim, -n sadece gürültü ekler ve okunabilirliği azaltır. Benzer şekilde, sıfır uzunluk veya ayarlanmamış test için [! [-z "$ var"] yerine "$ var"].
AllenHalsey

2
Yani ["vs grafiğiniz [-n"(OP'nin ilk sorusu) tamamen eşdeğer olduklarını gösteriyor, değil mi?
ocaklar

1
@hobs: Evet, hangisinin kullanılacağı hangisinin daha net olduğuna bağlıdır. Ayrıca, Bash kullanırken tercih edilen çift köşeli parantez formunu kullanırken eşdeğerlerinin de fark edeceksiniz.
sonraki duyuruya kadar duraklatıldı.

1
Bu yüzden, müthiş masanızı özetlemek için, boş olmayan dizeleri test etmenin daha net ("daha iyi") yolu[["
hobs

22

Bash söz konusu olduğunda daha güçlü kullanmak daha iyidir [[.

Olağan durumlar

if [[ $var ]]; then   # var is set and it is not empty
if [[ ! $var ]]; then # var is not set or it is set to an empty string

Yukarıdaki iki yapı temiz ve okunabilir görünüyor. Çoğu durumda yeterli olmalıdırlar.

Sözcük bölme ve globbing[[ tehlikesi olmadığından, içerideki değişken açılımları alıntılamamız gerekmediğini unutmayın .

Önlemek için shellcheck 'hakkında yumuşak şikayetleri s [[ $var ]]ve [[ ! $var ]]biz kullanabiliriz -nseçeneği.

Nadir durumlar

"Boş bir dizeye ayarlanmak" ile "hiç ayarlanmamak" arasında bir ayrım yapmak zorunda kaldığımız nadir durumlarda, bunları kullanabiliriz:

if [[ ${var+x} ]]; then           # var is set but it could be empty
if [[ ! ${var+x} ]]; then         # var is not set
if [[ ${var+x} && ! $var ]]; then # var is set and is empty

-vTesti de kullanabiliriz :

if [[ -v var ]]; then             # var is set but it could be empty
if [[ ! -v var ]]; then           # var is not set
if [[ -v var && ! $var ]]; then   # var is set and is empty
if [[ -v var && -z $var ]]; then  # var is set and is empty

İlgili yayınlar ve belgeler

Bu konuyla ilgili birçok yayın var. Burda biraz var:


9

İşte biraz daha test

Dize boş değilse true:

[ -n "$var" ]
[[ -n $var ]]
test -n "$var"
[ "$var" ]
[[ $var ]]
(( ${#var} ))
let ${#var}
test "$var"

Dize boşsa true:

[ -z "$var" ]
[[ -z $var ]]
test -z "$var"
! [ "$var" ]
! [[ $var ]]
! (( ${#var} ))
! let ${#var}
! test "$var"

Bu OP'nin neyin daha iyi bir yol olduğu sorusuna cevap vermiyor.
codeforester

0

Doğru cevap şudur:

if [[ -n $var ]] ; then
  blah
fi

Kullanımına dikkat [[...]]düzgün sizin için değişkenleri alıntı kolları.


2
Neden -nBash'te gerçekten ihtiyaç duyulmadığında kullanılsın?
codeforester

0

Boş bir ortam değişkenini değerlendirmenin alternatif ve belki de daha şeffaf bir yolu ...

  if [ "x$ENV_VARIABLE" != "x" ] ; then
      echo 'ENV_VARIABLE contains something'
  fi

10
Bu Bourne mermi günlerinden çok eski bir okul. Bu eski alışkanlığı devam ettirmeyin. bashöncekilerden daha keskin bir araçtır.
tbc0

2
POSIX standardının eskimiş olarak açıkça işaretlediği sözdiziminden kaçınıyorsanız, bash öncesi kabuklarla buna bile ihtiyacınız yoktur. POSIX uyumlu bir uygulama ile her kabukta [ "$ENV_VARIABLE" != "" ]çalışır - sadece bash değil, kül / tire / ksh / vb. test
Charles Duffy

... yani, testleri kullanmayın -aveya -obirleştirmeyin, bunun yerine kullanın [ ... ] && [ ... ]ya da [ ... ] || [ ... ]ve bir testte rasgele değişkenlerin verilerinin kullanılmasına uygulanabilecek tek köşe durumu açık bir şekilde kapatılır.
Charles Duffy

-2

case/esacTest etmek için kullanın :

case "$var" in
  "") echo "zero length";;
esac

12
Hayır lütfen. Amaçlanan bu değil case.
tbc0

2
caseikiden fazla alternatif olduğunda en iyi sonucu verir.
codeforester

casebu tür bir kullanım için tasarlanmamıştır.
Luis Lavaire
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.