Soru Bash’te dizinin boş olup olmadığını kontrol et


Komutum çalışırken farklı hata mesajları ile dolu bir dizi var.

Komut dosyasının sonunda boş olup olmadığını kontrol etmenin ve eğer varsa belirli bir işlem yapmanın bir yoluna ihtiyacım var.

Zaten normal bir VAR gibi davranmaya ve bunu kontrol etmek için -z kullanmaya çalıştım, ama işe yaramadı. Bash’te bir dizinin boş olup olmadığını kontrol etmenin bir yolu var mı?

Teşekkürler


82
2018-02-11 03:59


Menşei




Cevaplar:


Dizininiz varsayalım $errorsSadece elemanların sayısının sıfır olup olmadığını kontrol edin.

if [ ${#errors[@]} -eq 0 ]; then
    echo "No errors, hooray"
else
    echo "Oops, something went wrong..."
fi

113
2018-02-11 04:10



Lütfen bunu not al = String operatörüdür. Bu durumda iyi çalışıyor, ama uygun aritmetik operatörü kullanırdım -eq bunun yerine (sadece duruma geçmek istiyorum -ge veya -lt, vb.). - musiphil
İle çalışmıyor set -u: "ilişkisiz değişken" - dizi boşsa. - Igor
@ Igor: Bash 4.4'de benim için çalışıyor. set -u;  foo=();  [ ${#foo[@]} -eq 0 ] && echo empty. Eğer ben unset foosonra yazdırır foo: unbound variableama bu farklı: dizi değişkeni mevcut ve boş olmaktan ziyade hiç mevcut değil. - Peter Cordes
Kullanırken Bash 3.2'de (OSX) da test edildi set -u - öncelikle değişkeni ilan ettiğin sürece, bu mükemmel çalışır. - zeroimpl


Diziyi basit bir değişken olarak da değerlendirebilirsiniz. Bu şekilde, sadece kullanarak

if [ -z "$array" ]; then
    echo "Array empty"
else
    echo "Array non empty"
fi

veya diğer tarafı kullanarak

if [ -n "$array" ]; then
    echo "Array non empty"
else
    echo "Array empty"
fi

Bu çözümle ilgili sorun, bir dizi şöyle bildirilirse: array=('' foo). Açıkça görülmese de, bu kontroller diziyi boş olarak rapor edecektir. (teşekkürler @musiphil!)

kullanma [ -z "$array[@]" ] açıkça bir çözüm değildir. Kıvrımlı parantezleri belirtme, yorumlamaya çalışır $array bir dize olarak[@] Bu durumda basit bir değişmez dize) ve bu nedenle her zaman yanlış olarak bildirilir: "literal dize [@] boş mu? "Açıkçası değil.


6
2018-06-23 10:29



[ -z "$array" ] veya [ -n "$array" ] çalışmıyor Deneyin array=('' foo); [ -z "$array" ] && echo emptyve yazdı empty buna rağmen array açıkça boş değil. - musiphil
[[ -n "${array[*]}" ]] dizinin tamamını, sıfır olmayan uzunluk için kontrol ettiğiniz bir dize olarak enterpolasyon yapar. Düşünüyorsanız array=("" "") Boş olmak, iki boş öğeye sahip olmak yerine, bu yararlı olabilir. - Peter Cordes


Bu durumda genellikle aritmetik genişleme kullanırım:

if (( ${#a[@]} )); then
    echo not empty
fi

3
2017-08-02 06:04



Güzel ve temiz! Bunu sevdim. Ayrıca, dizinin ilk öğesinin her zaman izinsiz olduğunu fark ettim. (( ${#a} )) (ilk elemanın uzunluğu) da çalışacaktır. Ancak, bu başarısız olacak a=(''), buna karşılık (( ${#a[@]} )) cevapta verilen başarı başarılı olacaktır. - cxw


Kontrol ettim bash-4.4.0:

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]} ]]; then
        echo not empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

ve bash-4.1.5:

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]:+${array[@]}} ]]; then
        echo non-empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

İkinci durumda aşağıdaki yapıya ihtiyacınız vardır:

${array[@]:+${array[@]}}

boş veya unset dizisinde başarısız olmaması için. Eğer yaparsan set -eu Genelde yaptığım gibi. Bu daha katı hata kontrolü sağlar. itibaren dokümanlar:

-e

Tek bir basit komuttan (bkz. Basit Komutlar), bir listeden (Listelere bakın) veya bir bileşik komuttan (Bileşik Komutları'na bakın) oluşan bir boru hattı (bkz. Boru Hatları), sıfırdan farklı bir durum olduğunda hemen çıkın. Başarısız olan komut, komut satırının bir parçası olan komut dizisinin bir parçasıysa veya bir anahtar ifadesinde, bir if ifadesinde testin bir parçası olarak, && veya || son && veya ||, bir boru hattındaki herhangi bir komut ancak sonuncu komutu uygulayan komut hariç veya komutun dönüş durumu tersine çevrilmişse! Subshell dışındaki bir bileşik komutu sıfır olmayan bir durum döndürür, -e göz ardı edilirken bir komut başarısız oldu, kabuk çıkmaz. Ayarlanmışsa ERR'deki bir tuzak, kabuktan çıkmadan önce yürütülür.

Bu seçenek, kabuk ortamı ve her bir alt kabuk ortamına ayrı ayrı uygulanır (Komut Yürütme Ortamı'na bakın) ve alt kabuktaki tüm komutları yürütmeden önce alt kabukların çıkmasına neden olabilir.

Bileşik komut veya kabuk işlevi -e'nin göz ardı edildiği bir bağlamda yürütülürse, -e ayarlanmış ve bir komut döndürse bile -e ayarından bileşik komutu veya işlev gövdesi içinde yürütülen komutlardan hiçbiri etkilenmez. arıza durumu. Bileşik komut veya kabuk işlevi -e'nin yok sayıldığı bir bağlamda yürütülürken -e seçeneği ayarlanırsa, bu ayarın bileşik komutu veya işlev çağrısı içeren komut tamamlanana kadar herhangi bir etkisi olmaz.

-u

Parametre genişletme işlemi yapılırken, ‘@’ veya ‘*’ özel parametreleri dışındaki değişkenleri ve parametreleri, hata olarak ele alın. Standart hataya bir hata mesajı yazılacak ve etkileşimli olmayan bir kabuk çıkacaktır.

Buna ihtiyacınız yoksa, atlamaktan çekinmeyin :+${array[@]} Bölüm.

Ayrıca, kullanmak için gerekli olduğunu unutmayın [[ operatör burada [ alırsın:

$ cat 1.sh
#!/usr/bin/env bash
set -eu
array=(a b c d)
if [ "${array[@]}" ]; then
    echo non-empty
else
    echo empty
fi

$ ./1.sh
_/1.sh: line 4: [: too many arguments
empty

2
2017-12-04 14:58



İle -u aslında kullanmalısın ${array[@]+"${array[@]}"} cf stackoverflow.com/a/34361807/1237617 - Jakub Bochenski
@JakubBochenski Hangi bash versiyonunu konuşuyorsun? gist.github.com/x-yuri/d933972a2f1c42a49fc7999b8d5c50b9 - x-yuri
Tek parantez örneğindeki problem @elbette. Kullanabilirsin * dizi genişletme gibi [ "${array[*]}" ], yapamaz mısın? Yine de, [[ ayrıca iyi çalışıyor. Birden fazla boş dizeleri olan bir dizinin her ikisi için davranışı biraz şaşırtıcıdır. Her ikisi de [ ${#array[*]} ] ve [[ "${array[@]}" ]] yanlış array=() ve array=('') ama gerçek array=('' '') (iki veya daha fazla boş dizgiler). Herkes için bir veya daha fazla boş dizge istediyseniz, kullanabilirsiniz [ ${#array[@]} -gt 0 ]. Eğer hepsini yanlış istediyseniz, belki // Onları dışarı. - eisd
@eisd kullanabilirdim [ "${array[*]}" ]ama eğer böyle bir ifadeye girersem, ne yaptığını anlamak benim için daha zor olurdu. Dan beri [...] interpolasyon sonucu dizge bakımından çalışır. Aksine [[...]], enterpolasyonun ne olduğunun farkında olabilir. Yani bir diziden geçtiğini bilebilir. [[ ${array[@]} ]] bana "dizinin boş olmadığını kontrol et" olarak okur, [ "${array[*]}" ] "tüm dizi öğelerinin enterpolasyon sonucunun boş olmayan bir dize olup olmadığını kontrol edin". - x-yuri
... İki boş dizeleri olan davranışa gelince, bana hiç de şaşırtıcı değil. Şaşırtıcı olan, boş bir dizgenin davranışıdır. Ama tartışmasız makul. ilişkin [ ${#array[*]} ]Muhtemelen [ "${array[*]}" ]Çünkü ilke herhangi bir sayı için doğrudur. Öğelerin sayısı her zaman boş olmayan dizedir. İkincisi iki elemanla ilgili olarak, parantez içindeki ifade genişler. ' ' boş olmayan dize olan Gelince [[ ${array[@]} ]]Sadece iki öğenin herhangi bir dizisinin boş olmadığını düşünürler (ve haklı olarak). - x-yuri


Benim durumumda ikinci Cevap yeterli değildi çünkü whitespaces olabilirdi. Birlikte geldim:

if [ "$(echo -ne ${opts} | wc -m)" -eq 0 ]; then
  echo "No options"
else
  echo "Options found"
fi

0
2018-02-17 19:54



echo | wc kabuk yerleşik-insana kıyasla gereksiz yere verimsiz görünüyor. - Peter Cordes
@PeterCordes'i anladığımdan emin değilim, ikinci cevapları değiştirebilir miyim? [ ${#errors[@]} -eq 0 ]; Beyaz boşluk sorunu etrafında çalışmak için bir yol? Yerleşik olanı da tercih ederim. - Micha
Boşluk tam olarak nasıl bir soruna neden oluyor? $# bir sayıya genişler ve sonra bile iyi çalışır opts+=(""). Örneğin. unset opts;  opts+=("");opts+=(" "); echo "${#opts[@]}" ve ben alırım 2. Çalışmayan bir şeyin örneğini gösterir misiniz? - Peter Cordes
Çok uzun zaman önceydi. IIRC menşeli kaynak daima en az "" basılmıştır. Böylece, opts = "" veya opts = ("") için boş yeni satırı veya boş dizeyi göz ardı ederek 0 değil, 1'e ihtiyacım vardı. - Micha
Tamam, bu yüzden tedaviye ihtiyacın var. opts=("") aynı opts=()? Bu boş bir dizi değil, ancak boş bir diziyi veya boş ilk öğeyi kontrol edebilirsiniz. opts=("");  [[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty. Mevcut cevabınızın "seçenek yok" yazdığını unutmayın. opts=("" "-foo")Tamamen sahte olan ve bu davranışları yeniden üretir. Yapabilirdiniz [[ -z "${opts[*]}" ]] Sanırım tüm dizi elemanlarını düz bir dizgeye dönüştürmek, -z sıfır olmayan uzunluk için kontrol eder.  İlk elemanı kontrol etmek yeterli ise, -z "$opts" Eserleri. - Peter Cordes


Çift parantez kullanmayı tercih ederim:

if [[ !${array[@]} ]]
then
    echo "Array is empty"
else
    echo "Array is not empty"
fi

Çift parantez: https://stackoverflow.com/questions/669452/is-preferable-over-in-bash


0
2017-11-04 06:40