Menguji apakah variabel disetel di bash saat menggunakan "set -o nounset"

95

Kode berikut keluar dengan kesalahan variabel tak terikat. Bagaimana cara memperbaikinya, saat masih menggunakan set -oopsi kata benda?

#!/bin/bash

set -o nounset

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

echo "whatever"
vinodkone.dll
sumber

Jawaban:

98
#!/bin/bash

set -o nounset


VALUE=${WHATEVER:-}

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

echo "whatever"

Dalam kasus ini, VALUEberakhir menjadi string kosong jika WHATEVERtidak disetel. Kami menggunakan {parameter:-word}perluasan, yang dapat Anda cari di man bashbawah "Perluasan Parameter".

Angelom
sumber
14
ganti saja jika [! -z $ {VALUE}]; dengan if [! -z $ {APA PUN: -}];
Angelom
18
:-memeriksa apakah variabel tidak disetel atau kosong. Jika Anda ingin memeriksa hanya apakah itu tidak diset, gunakan -: VALUE=${WHATEVER-}. Juga, cara yang lebih mudah dibaca untuk memeriksa apakah suatu variabel kosong:if [ "${WHATEVER+defined}" = defined ]; then echo defined; else echo undefined; fi
l0b0
1
Juga, ini tidak akan berfungsi jika $WHATEVERhanya berisi spasi - Lihat jawaban saya.
l0b0
10
Apakah ada alasan untuk menggunakan " ! -z" daripada hanya " -n"?
Jonathan Hartley
31

Anda perlu mengutip variabel jika ingin mendapatkan hasil yang diharapkan:

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

Uji:

$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER='   '
$ check
not empty
l0b0
sumber
Saya mencoba ini dan saya terkejut karya ini ... Semuanya benar kecuali menurut "info bash", "${WHATEVER-}"harus memiliki ":"(kolon) sebelum "-"(dash) seperti: "${WHATEVER:-}", dan "${WHATEVER+defined}"harus memiliki usus sebelum "+"(plus) seperti: "${WHATEVER:+defined}". Bagi saya, itu bekerja dengan cara apa pun, dengan atau tanpa titik dua. Pada beberapa versi 'nix, ini mungkin tidak akan berfungsi tanpa menyertakan titik dua, jadi mungkin harus ditambahkan.
Kevin Fegan
8
Tidak, -, +, :+, dan :-semua didukung. Yang pertama mendeteksi apakah variabel disetel , dan yang terakhir mendeteksi apakah itu disetel atau kosong . Dari man bash: "Menghilangkan titik dua menghasilkan pengujian hanya untuk parameter yang tidak disetel."
l0b0
1
Nevermind =). Anda benar. Saya tidak tahu bagaimana saya melewatkannya.
Kevin Fegan
Dari dokumen : Dengan kata lain, jika titik dua disertakan, operator menguji keberadaan kedua parameter dan nilainya bukan null; jika titik dua dihilangkan, operator hanya menguji keberadaannya.
Acumenus
8

Bagaimana dengan oneliner?

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

-z memeriksa variabel kosong atau tidak disetel

NublaII
sumber
2
Tidak, -zhanya memeriksa apakah parameter berikutnya kosong. -zhanyalah argumen dari [perintah. Ekspansi variabel terjadi sebelum [ -zdapat melakukan apapun.
dolmen
1
Ini sepertinya solusi yang tepat, karena tidak menghasilkan kesalahan jika $ VAR tidak disetel. @dolmen dapatkah Anda memberikan contoh ketika itu tidak akan berhasil?
Chris Stryczynski
@dolmen telah membaca berbagai sumber bash tentang ekspansi param dan menemukan jawaban lain terlalu rumit, saya tidak melihat ada yang salah dengan yang ini. jadi "klarifikasi" Anda, meskipun secara teknis benar, tampaknya agak tidak berguna dalam praktiknya, kecuali Anda perlu membedakan tidak disetel vs kosong. Saya menguji tidak disetel, kosong dan tidak kosong, (bash 4) dan cukup banyak melakukan apa yang diiklankan setiap kali.
JL Peyret
8

Asumsi:

$ 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

Jika Anda ingin skrip non-interaktif mencetak kesalahan dan keluar jika variabel null atau tidak disetel:

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

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

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

Jika Anda tidak ingin skrip keluar:

$ [[ "${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.

Anda bahkan dapat menggunakan [dan ]sebagai pengganti [[dan yang ]]lebih baru, tetapi yang terakhir lebih disukai di Bash.

Perhatikan apa yang dilakukan titik dua di atas. Dari dokumen :

Dengan kata lain, jika titik dua disertakan, operator menguji keberadaan kedua parameter dan nilainya bukan null; jika titik dua dihilangkan, operator hanya menguji keberadaannya.

Tampaknya tidak perlu -natau -z.

Singkatnya, saya biasanya hanya menggunakan [[ "${VAR:?}" ]]. Per contoh, ini mencetak kesalahan dan keluar jika variabel null atau tidak disetel.

Acumenus
sumber
4

Kamu bisa memakai

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

tapi

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

mungkin lebih mudah dibaca.

Aleš Friedl
sumber
Perbandingan string harus menggunakan =operator standar (POSIX) , bukan ==untuk membantu portabilitas, dan [sebaliknya [[jika memungkinkan.
Jens
2
@Jens Pertanyaannya khusus untuk pesta dan termasuk set -o nounsetyang khusus untuk pesta. Jika Anda meletakkan a #!/bin/bashdi bagian atas skrip Anda, sebenarnya yang terbaik adalah menggunakan penyempurnaan bash.
Bruno Bronosky
0

Meskipun ini tidak persis kasus penggunaan meminta di atas, saya telah menemukan bahwa jika Anda ingin menggunakan nounset(atau-u ) perilaku default adalah salah satu yang ingin: untuk keluar nol dengan pesan deskriptif.

Butuh waktu cukup lama bagi saya untuk menyadari hal ini sehingga saya pikir itu layak untuk diposting sebagai solusi.

Jika yang Anda inginkan hanyalah menggemakan hal lain saat keluar, atau melakukan pembersihan, Anda dapat menggunakan jebakan.

The :-operator adalah mungkin apa yang Anda inginkan sebaliknya.

Max Bileschi
sumber