Saya memiliki array yang diisi dengan pesan kesalahan yang berbeda saat skrip saya berjalan.
Saya perlu cara untuk memeriksa apakah kosong atau tidak pada akhir skrip dan mengambil tindakan tertentu jika itu.
Saya sudah mencoba memperlakukannya seperti VAR normal dan menggunakan -z untuk memeriksanya, tetapi itu sepertinya tidak berhasil. Apakah ada cara untuk memeriksa apakah array kosong atau tidak di Bash?
=
adalah operator string. Kebetulan berfungsi dengan baik dalam kasus ini, tetapi saya akan menggunakan operator aritmatika yang tepat-eq
sebagai gantinya (kalau-kalau saya ingin beralih ke-ge
atau-lt
, dll.).set -u
: "variabel tidak terikat" - jika array kosong.set -u;
foo=();
[ ${#foo[@]} -eq 0 ] && echo empty
. Jika sayaunset foo
, maka ia mencetakfoo: unbound variable
, tetapi itu berbeda: variabel array tidak ada sama sekali, bukan yang ada dan kosong.set -u
- selama Anda mendeklarasikan variabel Anda terlebih dahulu, ini berfungsi dengan baik.Saya biasanya menggunakan ekspansi aritmatika dalam hal ini:
sumber
(( ${#a} ))
(panjang elemen pertama) akan bekerja juga. Namun, itu akan gagala=('')
, sedangkan yang(( ${#a[@]} ))
diberikan dalam jawaban akan berhasil.Anda juga dapat mempertimbangkan array sebagai variabel sederhana. Dengan begitu, hanya menggunakan
atau menggunakan sisi lain
Masalah dengan solusi itu adalah bahwa jika sebuah array dideklarasikan seperti ini:
array=('' foo)
. Pemeriksaan ini akan melaporkan array sebagai kosong, sementara jelas tidak. (terima kasih @musiphil!)Menggunakan
[ -z "$array[@]" ]
jelas bukan solusi juga. Tidak menentukan kurung keriting mencoba menafsirkan$array
sebagai string ([@]
dalam hal ini string literal sederhana) dan karenanya selalu dilaporkan sebagai salah: "apakah string literal[@]
kosong?" Jelas tidak.sumber
[ -z "$array" ]
atau[ -n "$array" ]
tidak bekerja Cobaarray=('' foo); [ -z "$array" ] && echo empty
, dan itu akan dicetakempty
walaupunarray
jelas tidak kosong.[[ -n "${array[*]}" ]]
interpolasi seluruh array sebagai string, yang Anda periksa panjangnya tidak nol. Jika Anda menganggaparray=("" "")
kosong, daripada memiliki dua elemen kosong, ini mungkin berguna.[[ -n " " ]]
"benar," yang sangat disayangkan. Komentar Anda persis seperti yang ingin saya lakukan.set -x
menunjukkan bagaimana itu mengembang. Saya kira saya tidak menguji komentar itu sebelum memposting. >. <Anda dapat membuatnya bekerja dengan mengaturIFS=''
(menyimpan / mengembalikannya di sekitar pernyataan ini), karena"${array[*]}"
ekspansi memisahkan elemen dengan karakter pertama IFS. (Atau spasi jika tidak disetel). Tetapi " Jika IFS adalah nol, parameter digabungkan tanpa campur tangan pemisah. " (Docs untuk $ * posisi params, tapi saya anggap sama untuk array).Saya memeriksanya dengan
bash-4.4.0
:dan
bash-4.1.5
:Dalam kasus terakhir, Anda memerlukan konstruk berikut:
agar tidak gagal pada array kosong atau tidak disetel. Itu jika Anda
set -eu
suka saya biasanya. Ini memberikan pemeriksaan kesalahan yang lebih ketat. Dari dokumen :Jika Anda tidak membutuhkannya, jangan ragu untuk menghilangkan
:+${array[@]}
bagiannya.Perhatikan juga, bahwa penting untuk menggunakan
[[
operator di sini, dengan[
Anda dapat:sumber
-u
Anda harus benar-benar menggunakan${array[@]+"${array[@]}"}
cf stackoverflow.com/a/34361807/1237617@
, tentu saja. Anda bisa menggunakan*
ekspansi array seperti[ "${array[*]}" ]
, bukan? Meski begitu,[[
juga berfungsi dengan baik. Perilaku keduanya untuk array dengan banyak string kosong sedikit mengejutkan. Keduanya[ ${#array[*]} ]
dan[[ "${array[@]}" ]]
salah untukarray=()
danarray=('')
tetapi berlaku untukarray=('' '')
(dua atau lebih string kosong). Jika Anda ingin satu atau lebih string kosong menjadi kenyataan, Anda dapat menggunakannya[ ${#array[@]} -gt 0 ]
. Jika Anda ingin semuanya salah, Anda mungkin bisa//
mengeluarkannya.[ "${array[*]}" ]
, tetapi jika saya mengalami ekspresi seperti itu, akan lebih sulit bagi saya untuk memahami apa fungsinya. Sejak[...]
beroperasi dalam hal string pada hasil interpolasi. Berbeda dengan[[...]]
, yang bisa mewaspadai apa yang diinterpolasi. Artinya, bisa tahu bahwa itu dilewatkan array.[[ ${array[@]} ]]
berbunyi bagi saya sebagai "periksa apakah array tidak kosong", sementara[ "${array[*]}" ]
sebagai "periksa apakah hasil interpolasi semua elemen array adalah string yang tidak kosong".[ ${#array[*]} ]
, Anda mungkin dimaksudkan[ "${array[*]}" ]
, karena yang pertama berlaku untuk sejumlah elemen. Karena jumlah elemen selalu non-string kosong. Mengenai yang terakhir dengan dua elemen, ekspresi di dalam tanda kurung berkembang menjadi' '
string yang tidak kosong. Adapun[[ ${array[@]} ]]
, mereka hanya berpikir (dan memang demikian) bahwa setiap array dari dua elemen tidak kosong.Jika Anda ingin mendeteksi array dengan elemen kosong , seperti
arr=("" "")
kosong, sama denganarr=()
Anda dapat menempelkan semua elemen bersama dan memeriksa apakah hasilnya nol panjang. (Membangun salinan rata isi array tidak ideal untuk kinerja jika array bisa sangat besar. Tapi semoga Anda tidak menggunakan bash untuk program seperti itu ...)
Tetapi
"${arr[*]}"
berkembang dengan elemen yang dipisahkan oleh karakter pertamaIFS
. Jadi Anda perlu menyimpan / mengembalikan IFS dan lakukanIFS=''
untuk membuat ini berfungsi, atau periksa apakah panjang string == # elemen array - 1. (Arrayn
elemen memilikin-1
pemisah). Untuk mengatasinya secara off-by-one, akan lebih mudah untuk menggabungkannya dengan 1test case dengan
set -x
Sayangnya ini gagal untuk
arr=()
:[[ 1 -ne 0 ]]
. Jadi, Anda perlu memeriksa array yang benar-benar kosong terlebih dahulu secara terpisah.Atau dengan
IFS=''
. Mungkin Anda ingin menyimpan / mengembalikan IFS daripada menggunakan subkulit, karena Anda tidak bisa mendapatkan hasil dari subkulit dengan mudah.contoh:
tidak bekerja dengan
arr=()
- itu masih hanya string kosong.sumber
[[ "${arr[*]}" = *[![:space:]]* ]]
, karena saya dapat mengandalkan setidaknya satu karakter non-WS.arr=(" ")
.Dalam kasus saya, Jawaban kedua tidak cukup karena mungkin ada ruang putih. Saya datang dengan:
sumber
echo | wc
tampaknya tidak efisien dibandingkan menggunakan shell built-in.[ ${#errors[@]} -eq 0 ];
dengan cara mengatasi masalah spasi putih? Saya juga lebih suka built-in.$#
meluas ke angka, dan berfungsi dengan baik bahkan setelahnyaopts+=("")
. misunset opts;
opts+=("");opts+=(" "); echo "${#opts[@]}"
dan saya dapatkan2
. Bisakah Anda menunjukkan contoh sesuatu yang tidak berhasil?opts=("")
yang samaopts=()
? Itu bukan array kosong, tetapi Anda bisa memeriksa array kosong atau elemen pertama kosongopts=("");
[[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty
. Perhatikan bahwa jawaban Anda saat ini mengatakan "tidak ada opsi" untukopts=("" "-foo")
, yang benar-benar palsu, dan ini mereproduksi perilaku itu. Anda bisa[[ -z "${opts[*]}" ]]
menebak, untuk menginterpolasi semua elemen array menjadi string datar, yang-z
memeriksa panjang tidak nol. Jika memeriksa elemen pertama sudah cukup,-z "$opts"
berfungsi.Saya lebih suka menggunakan kurung ganda:
sumber