Pertanyaan Periksa apakah larik kosong di Bash


Saya memiliki larik yang dipenuhi dengan pesan kesalahan yang berbeda saat skrip saya berjalan.

Saya perlu cara untuk memeriksa apakah kosong tidak di bagian akhir skrip dan mengambil tindakan tertentu jika itu ada.

Saya sudah mencoba memperlakukannya seperti VAR biasa dan menggunakan -z untuk memeriksanya, tetapi tampaknya itu tidak berhasil. Apakah ada cara untuk memeriksa apakah array kosong atau tidak di Bash?

Terima kasih


82
2018-02-11 03:59






Jawaban:


Misalkan array Anda $errors, cukup periksa untuk melihat apakah hitungan elemen adalah nol.

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

113
2018-02-11 04:10



Harap dicatat bahwa = adalah operator string. Ini terjadi untuk bekerja dengan baik dalam hal ini, tapi saya akan menggunakan operator aritmatika yang tepat -eq sebaliknya (kalau-kalau saya ingin beralih ke -ge atau -lt, dll.). - musiphil
Tidak bekerja dengan set -u: "variabel terikat" - jika array kosong. - Igor
@Igor: Bekerja untukku di Bash 4.4. set -u;  foo=();  [ ${#foo[@]} -eq 0 ] && echo empty. Jika saya unset foo, lalu dicetak foo: unbound variable, tapi itu berbeda: variabel array tidak ada sama sekali, daripada ada dan kosong. - Peter Cordes
Juga diuji dalam Bash 3.2 (OSX) saat menggunakan set -u - selama Anda menyatakan variabel Anda terlebih dahulu, ini berfungsi dengan sempurna. - zeroimpl


Anda juga dapat menganggap larik sebagai variabel sederhana. Dengan cara itu, hanya menggunakan

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

atau menggunakan sisi lain

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

Masalah dengan solusi itu adalah jika array dinyatakan seperti ini: array=('' foo). Pemeriksaan ini akan melaporkan larik sebagai kosong, sementara itu jelas tidak. (terima kasih @musiphil!)

Menggunakan [ -z "$array[@]" ] jelas bukan solusi juga. Tidak menentukan kurung kurawal mencoba menafsirkan $array sebagai string ([@] dalam hal ini string literal sederhana) dan karena itu selalu dilaporkan sebagai false: "adalah string literal [@] kosong? "Jelas tidak.


6
2018-06-23 10:29



[ -z "$array" ] atau [ -n "$array" ] tidak berfungsi. Mencoba array=('' foo); [ -z "$array" ] && echo empty, dan itu akan dicetak empty meskipun array jelas tidak kosong. - musiphil
[[ -n "${array[*]}" ]] interpolasi seluruh array sebagai string, yang Anda periksa untuk panjang non-nol. Jika Anda mempertimbangkan array=("" "") untuk menjadi kosong, daripada memiliki dua elemen kosong, ini mungkin berguna. - Peter Cordes


Saya biasanya menggunakan ekspansi aritmatika dalam hal ini:

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

3
2017-08-02 06:04



Bagus dan bersih! Saya suka itu. Saya juga mencatat bahwa jika elemen pertama dari array selalu nonempty, (( ${#a} )) (panjang elemen pertama) akan berfungsi juga. Namun, itu akan gagal a=(''), sedangkan (( ${#a[@]} )) diberikan dalam jawaban akan berhasil. - cxw


Saya sudah memeriksanya 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

dan 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

Dalam kasus terakhir, Anda memerlukan konstruksi berikut:

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

agar tidak gagal pada array kosong atau tidak disetel. Itu jika Anda melakukannya set -eu seperti biasanya saya lakukan. Ini menyediakan pemeriksaan kesalahan yang lebih ketat. Dari dokumen:

-e

Segera keluar jika sebuah pipa (lihat Saluran Pipa), yang mungkin terdiri dari satu perintah sederhana (lihat Perintah Sederhana), daftar (lihat Daftar), atau perintah majemuk (lihat Perintah Gabungan) mengembalikan status bukan nol. Shell tidak keluar jika perintah yang gagal adalah bagian dari daftar perintah segera setelah beberapa saat atau sampai kata kunci, bagian dari tes dalam pernyataan if, bagian dari setiap perintah yang dijalankan dalam && atau || daftar kecuali perintah mengikuti perintah akhir && atau ||, apa pun dalam pipa tetapi yang terakhir, atau jika status kembali perintah dibalikkan dengan!. Jika perintah majemuk selain subkulit mengembalikan status bukan nol karena perintah gagal saat -e diabaikan, shell tidak keluar. Suatu perangkap pada ERR, jika diset, dijalankan sebelum shell keluar.

Opsi ini berlaku untuk lingkungan shell dan setiap lingkungan subkunci secara terpisah (lihat Lingkungan Eksekusi Perintah), dan dapat menyebabkan subkelop keluar sebelum menjalankan semua perintah dalam subkulit.

Jika perintah majemuk atau fungsi shell mengeksekusi dalam konteks di mana -e diabaikan, tidak satu pun perintah yang dieksekusi dalam perintah majemuk atau badan fungsi akan dipengaruhi oleh pengaturan -e, bahkan jika -e diatur dan perintah mengembalikan status kegagalan. Jika perintah majemuk atau fungsi shell set -e saat mengeksekusi dalam konteks di mana -e diabaikan, pengaturan itu tidak akan memiliki efek apa pun sampai perintah gabungan atau perintah yang berisi panggilan fungsi selesai.

-u

Perlakukan variabel dan parameter yang tidak disetel selain parameter khusus ‘@’ atau ‘*’ sebagai kesalahan saat melakukan ekspansi parameter. Pesan kesalahan akan ditulis ke kesalahan standar, dan shell non-interaktif akan keluar.

Jika Anda tidak membutuhkannya, jangan ragu untuk menghilangkannya :+${array[@]} bagian.

Juga perlu dicatat, bahwa itu penting untuk digunakan [[ operator di sini, dengan [ Anda mendapatkan:

$ 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



Dengan -u Anda benar-benar harus menggunakan ${array[@]+"${array[@]}"} cf stackoverflow.com/a/34361807/1237617 - Jakub Bochenski
@JakubBochenski Versi bash mana yang kamu bicarakan? gist.github.com/x-yuri/d933972a2f1c42a49fc7999b8d5c50b9 - x-yuri
Masalah dalam contoh kurung tunggal adalah @tentu saja. Anda bisa menggunakannya * ekspansi array seperti [ "${array[*]}" ], bisakah kamu tidak? Masih, [[ juga berfungsi dengan baik. Perilaku keduanya untuk sebuah array dengan beberapa string kosong sedikit mengejutkan. Kedua [ ${#array[*]} ] dan [[ "${array[@]}" ]] salah untuk array=() dan array=('') tetapi berlaku untuk array=('' '') (dua atau lebih string kosong). Jika Anda ingin satu atau lebih string kosong untuk semua memberi benar, Anda bisa menggunakan [ ${#array[@]} -gt 0 ]. Jika Anda ingin semuanya salah, Anda mungkin bisa // mereka keluar. - eisd
@ eisd saya bisa digunakan [ "${array[*]}" ], tetapi jika saya mengalami ekspresi seperti itu, akan lebih sulit bagi saya untuk memahami apa yang dilakukannya. Sejak [...] beroperasi dalam hal string pada hasil interpolasi. Sebagai lawan [[...]], yang dapat mengetahui apa yang diinterpolasi. Artinya, ia dapat mengetahui bahwa ia telah melewati sebuah array. [[ ${array[@]} ]] membaca kepada saya sebagai "periksa apakah array tidak kosong", sementara [ "${array[*]}" ] sebagai "periksa apakah hasil interpolasi dari semua elemen array adalah string yang tidak kosong". - x-yuri
... Adapun perilaku dengan dua string kosong itu sama sekali tidak mengherankan bagi saya. Yang mengejutkan adalah perilaku dengan satu string kosong. Namun bisa dibilang masuk akal. Mengenai [ ${#array[*]} ], mungkin maksud Anda [ "${array[*]}" ], karena yang pertama berlaku untuk sejumlah elemen. Karena jumlah elemen selalu string tidak kosong. Mengenai yang terakhir dengan dua elemen, ekspresi di dalam kurung meluas ' ' yang merupakan string tidak kosong. Seperti untuk [[ ${array[@]} ]], mereka hanya berpikir (dan memang demikian) bahwa array apa pun dari dua elemen tidak kosong. - x-yuri


Dalam kasus saya, itu jawaban kedua tidak cukup karena bisa ada spasi putih. Saya datang bersama dengan:

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 nampaknya tidak efisien dibandingkan menggunakan shell built-in. - Peter Cordes
Tidak yakin apakah saya mengerti @PeterCordes, dapatkah saya mengubah jawaban kedua ' [ ${#errors[@]} -eq 0 ]; dengan cara mengatasi masalah whitespace? Saya juga lebih suka built-in. - Micha
Bagaimana tepatnya ruang kosong menyebabkan masalah? $# meluas ke angka, dan berfungsi dengan baik bahkan setelah opts+=(""). misalnya unset opts;  opts+=("");opts+=(" "); echo "${#opts[@]}" dan saya dapatkan 2. Bisakah Anda menunjukkan contoh sesuatu yang tidak berfungsi? - Peter Cordes
Sudah lama sekali. IIRC sumber asal selalu dicetak setidaknya "". Jadi, untuk opts = "" atau opts = ("") Saya perlu 0, bukan 1, mengabaikan baris baru kosong atau string kosong. - Micha
Ok, jadi kamu harus traktir opts=("") sama seperti opts=()? Itu bukan larik kosong, tetapi Anda bisa memeriksa larik kosong atau elemen kosong pertama dengan opts=("");  [[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty. Perhatikan bahwa jawaban Anda saat ini mengatakan "tidak ada opsi" untuk opts=("" "-foo"), yang benar-benar palsu, dan ini mereproduksi perilaku itu. Anda bisa [[ -z "${opts[*]}" ]] Saya kira, untuk menginterpolasi semua elemen array menjadi string datar, yang -z cek untuk panjang tidak nol.  Jika memeriksa elemen pertama sudah cukup, -z "$opts" bekerja. - Peter Cordes


Saya lebih suka menggunakan tanda kurung ganda:

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

Kurung ganda: https://stackoverflow.com/questions/669452/is-preferable-over-in-bash


0
2017-11-04 06:40