harap biasakan menggunakan [-z "$ mystr"] sebagai lawan dari [-z $ mystr]
Charles Duffy
bagaimana melakukan hal yang terbalik? Maksud saya ketika string tidak null
Buka jalan
1
@flow: Bagaimana dengan[ -n "${VAR+x}"] && echo not null
Lekensteyn
1
@CharlesDuffy Saya pernah membaca ini sebelumnya di banyak sumber online. Mengapa ini lebih disukai?
meraba
6
@ Ayos karena jika Anda tidak memiliki tanda kutip, konten variabel adalah string-split dan globbed; jika ini adalah string kosong, itu menjadi [ -z ]bukan [ -z "" ]; jika ia memiliki ruang, itu [ -z "my" "test" ]bukannya [ -z my test ]; dan jika itu [ -z * ], maka *diganti dengan nama-nama file di direktori Anda.
Charles Duffy
Jawaban:
138
Saya pikir jawaban Anda setelah tersirat (jika tidak dinyatakan) oleh Vinko 's jawaban , meskipun tidak terbilang sederhana. Untuk membedakan apakah VAR diatur tetapi kosong atau tidak disetel, Anda dapat menggunakan:
if[-z "${VAR+xxx}"];then echo VAR is not set at all;fiif[-z "$VAR"]&&["${VAR+xxx}"="xxx"];then echo VAR is set but empty;fi
Anda mungkin dapat menggabungkan dua tes pada baris kedua menjadi satu dengan:
if[-z "$VAR"-a "${VAR+xxx}"="xxx"];then echo VAR is set but empty;fi
Namun, jika Anda membaca dokumentasi untuk Autoconf, Anda akan menemukan bahwa mereka tidak merekomendasikan menggabungkan istilah dengan ' -a' dan merekomendasikan menggunakan tes sederhana terpisah dikombinasikan dengan &&. Saya belum menemukan sistem di mana ada masalah; itu tidak berarti mereka tidak pernah ada (tetapi mereka mungkin sangat langka hari ini, bahkan jika mereka tidak langka di masa lalu).
Baru-baru ini saya ditanya melalui email tentang jawaban ini dengan pertanyaan:
Anda menggunakan dua tes, dan saya mengerti yang kedua dengan baik, tetapi bukan yang pertama. Lebih tepatnya saya tidak mengerti perlunya ekspansi variabel
if[-z "${VAR+xxx}"];then echo VAR is not set at all;fi
Bukankah ini akan mencapai hal yang sama?
if[-z "${VAR}"];then echo VAR is not set at all;fi
Pertanyaan wajar - jawabannya adalah 'Tidak, alternatif Anda yang lebih sederhana tidak melakukan hal yang sama'.
Misalkan saya menulis ini sebelum ujian Anda:
VAR=
Tes Anda akan mengatakan "VAR tidak disetel sama sekali", tetapi tes saya akan mengatakan (dengan implikasi karena tidak menggemakan apa pun) "VAR diatur tetapi nilainya mungkin kosong". Coba skrip ini:
(
unset VAR
if[-z "${VAR+xxx}"];then echo JL:1 VAR is not set at all;fiif[-z "${VAR}"];then echo MP:1 VAR is not set at all;fi
VAR=if[-z "${VAR+xxx}"];then echo JL:2 VAR is not set at all;fiif[-z "${VAR}"];then echo MP:2 VAR is not set at all;fi)
Outputnya adalah:
JL:1 VAR is not set at all
MP:1 VAR is not set at all
MP:2 VAR is not set at all
Dalam pasangan tes kedua, variabel diatur, tetapi diatur ke nilai kosong. Ini adalah perbedaan yang dibuat oleh ${VAR=value}dan ${VAR:=value}notasi. Ditto untuk ${VAR-value}dan ${VAR:-value}, dan ${VAR+value}dan ${VAR:+value}, dan seterusnya.
Sebagai Gili menunjukkan dalam bukunya jawaban , jika Anda menjalankan bashdengan set -o nounsetpilihan, maka jawaban dasar di atas gagal dengan unbound variable. Itu mudah diatasi:
if[-z "${VAR+xxx}"];then echo VAR is not set at all;fiif[-z "${VAR-}"]&&["${VAR+xxx}"="xxx"];then echo VAR is set but empty;fi
Atau Anda dapat membatalkan set -o nounsetopsi dengan set +u( set -usetara dengan set -o nounset).
Satu-satunya masalah yang saya miliki dengan jawaban ini adalah bahwa ia menyelesaikan tugasnya dengan cara yang agak tidak langsung dan tidak jelas.
Swiss
3
Bagi mereka yang ingin mencari deskripsi tentang arti di atas di halaman bash man, lihat bagian "Parameter Ekspansi" dan kemudian untuk teks ini: "Ketika tidak melakukan ekspansi substring, menggunakan formulir yang didokumentasikan di bawah ini, uji bash untuk parameter yang tidak disetel atau null ['null' yang berarti string kosong]. Menghilangkan titik dua menghasilkan tes hanya untuk parameter yang tidak disetel (...) $ {parameter: + kata}: Gunakan Nilai Alternatif. Jika parameter adalah nol atau tidak disetel, tidak ada yang diganti, kalau tidak ekspansi kata akan diganti. "
David Tonhofer
2
@ Swiss Ini bukan tidak jelas atau tidak langsung, tetapi idiomatik. Mungkin bagi seorang programmer yang tidak terbiasa dengan ${+}dan ${-}tidak jelas, tetapi keakraban dengan konstruksi itu sangat penting jika seseorang ingin menjadi pengguna shell yang kompeten.
Saya melakukan banyak pengujian pada ini; karena hasil dalam skrip saya tidak konsisten. Saya sarankan rakyat melihat ke dalam " [ -v VAR ]" pendekatan dengan pesta -s v4.2 dan di luar .
-z berfungsi untuk variabel yang tidak terdefinisi juga. Untuk membedakan antara yang tidak terdefinisi dan yang didefinisikan, Anda akan menggunakan hal-hal yang tercantum di sini atau, dengan penjelasan yang lebih jelas, di sini .
Cara terbersih adalah menggunakan ekspansi seperti dalam contoh-contoh ini. Untuk mendapatkan semua opsi Anda, periksa bagian Ekspansi Parameter dari manual.
Kata alternatif:
~$ unset FOO
~$ if test ${FOO+defined};then echo "DEFINED";fi~$ FOO=""~$ if test ${FOO+defined};then echo "DEFINED";fi
DEFINED
Nilai default:
~$ FOO=""~$ if test "${FOO-default value}";then echo "UNDEFINED";fi~$ unset FOO
~$ if test "${FOO-default value}";then echo "UNDEFINED";fi
UNDEFINED
Tentu saja Anda akan menggunakan salah satu dari ini secara berbeda, menempatkan nilai yang Anda inginkan daripada 'nilai default' dan menggunakan ekspansi secara langsung, jika sesuai.
Tapi saya ingin membedakan antara apakah string "" atau belum pernah didefinisikan. Apakah itu mungkin?
Setjmp
1
jawaban ini memberi tahu bagaimana membedakan antara dua kasus itu; ikuti bash faq link yang disediakannya untuk diskusi lebih lanjut.
Charles Duffy
1
Saya menambahkannya setelah komentarnya, Charles
Vinko Vrsalovic
2
Cari "Parameter Expansion" di halaman bash man untuk semua "trik" ini. Misalnya $ {foo: -default} untuk menggunakan nilai default, $ {foo: = default} untuk menetapkan nilai default, $ {foo:? Pesan kesalahan} untuk menampilkan pesan kesalahan jika foo tidak disetel, dll.
Jouni K Seppänen
18
Panduan skrip bash tingkat lanjut, 10.2. Substitusi Parameter:
$ {var + blahblah}: jika var didefinisikan, 'blahblah' diganti dengan ekspresi, kalau tidak null diganti
$ {var-blahblah}: jika var didefinisikan, itu sendiri diganti, lain 'blahblah' diganti
$ {var? blahblah}: jika var didefinisikan, ia diganti, kalau tidak fungsi tersebut ada dengan 'blahblah' sebagai pesan kesalahan.
untuk mendasarkan logika program Anda pada apakah variabel $ mystr didefinisikan atau tidak, Anda dapat melakukan hal berikut:
isdefined=0
${mystr+ export isdefined=1}
sekarang, jika isdefined = 0 maka variabel tidak terdefinisi, jika isdefined = 1 variabel didefinisikan
Cara memeriksa variabel ini lebih baik daripada jawaban di atas karena lebih elegan, mudah dibaca, dan jika bash shell Anda dikonfigurasi untuk kesalahan pada penggunaan variabel yang tidak ditentukan (set -u), skrip akan berakhir sebelum waktunya.
Hal berguna lainnya:
untuk memiliki nilai default 7 ditugaskan ke $ mystr jika itu tidak terdefinisi, dan biarkan utuh jika tidak:
mystr=${mystr-7}
untuk mencetak pesan kesalahan dan keluar dari fungsi jika variabel tidak terdefinisi:
: ${mystr? not defined}
Berhati-hatilah di sini bahwa saya menggunakan ':' agar tidak memiliki isi $ mystr dieksekusi sebagai perintah jika itu didefinisikan.
Saya tidak tahu tentang itu? sintaks untuk variabel BASH. Itu tangkapan yang bagus.
Swiss
Ini bekerja juga dengan referensi variabel tidak langsung. Ini melewati: var= ; varname=var ; : ${!varname?not defined}dan ini berakhir: varname=var ; : ${!varname?not defined}. Tetapi itu adalah kebiasaan yang baik untuk digunakan set -uyang melakukan hal yang sama lebih mudah.
ceving
11
Ringkasan tes.
[-n "$var"]&& echo "var is set and not empty"[-z "$var"]&& echo "var is unset or empty"["${var+x}"="x"]&& echo "var is set"# may or may not be empty[-n "${var+x}"]&& echo "var is set"# may or may not be empty[-z "${var+x}"]&& echo "var is unset"[-z "${var-x}"]&& echo "var is set and empty"
Latihan yang bagus dalam bash. Terkadang path file memiliki spasi, atau untuk melindungi terhadap injeksi perintah
k107
1
Saya pikir dengan ${var+x}itu tidak perlu kecuali jika nama variabel diperbolehkan memiliki ruang di dalamnya.
Anne van Rossum
Bukan hanya praktik yang baik; itu diperlukan dengan [untuk mendapatkan hasil yang benar. Jika vartidak disetel atau kosong, [ -n $var ]kurangi [ -n ]yang memiliki status keluar 0, sementara [ -n "$var" ]memiliki status keluar yang diharapkan (dan benar) dari 1.
chepner
5
https://stackoverflow.com/a/9824943/14731 berisi jawaban yang lebih baik (jawaban yang lebih mudah dibaca dan berfungsi dengan set -o nounsetdiaktifkan). Ini kira-kira berfungsi seperti ini:
if[-n "${VAR-}"];then
echo "VAR is set and is not empty"elif["${VAR+DEFINED_BUT_EMPTY}"="DEFINED_BUT_EMPTY"];then
echo "VAR is set, but empty"else
echo "VAR is not set"fi
Tidak dapat menemukan ini di halaman manual mana pun (untuk bash atau tes) tetapi itu berfungsi untuk saya .. Tahu versi apa ini ditambahkan?
Ash Berlin-Taylor
1
Ini didokumentasikan dalam Ekspresi Bersyarat , dirujuk dari testoperator di ujung ekor bagian Bourne Shell Builtins . Saya tidak tahu kapan itu ditambahkan, tetapi tidak dalam versi Apple bash(berdasarkan bash3.2.51), jadi mungkin fitur 4.x.
Jonathan Leffler
1
Ini tidak bekerja untuk saya GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu). Kesalahannya adalah -bash: [: -v: unary operator expected. Per komentar di sini , membutuhkan minimal 4.2 bash untuk bekerja.
Acumenus
Terima kasih telah memeriksa kapan tersedia. Saya telah menggunakannya sebelumnya pada berbagai sistem, tetapi kemudian tiba-tiba itu tidak berfungsi. Saya datang ke sini karena penasaran dan ya, tentu saja bash pada sistem ini adalah bash 3.x.
bukan untuk menumpahkan motor ini lebih jauh, tetapi ingin menambahkan
shopt -s -o nounset
adalah sesuatu yang dapat Anda tambahkan ke bagian atas skrip, yang akan kesalahan jika variabel tidak dideklarasikan di mana pun dalam skrip. Pesan yang Anda lihat adalah unbound variable, tetapi seperti yang disebutkan orang lain, pesan itu tidak akan menangkap string kosong atau nilai nol. Untuk memastikan nilai individual apa pun tidak kosong, kami dapat menguji variabel yang diperluas dengan ${mystr:?}, juga dikenal sebagai ekspansi tanda dolar, yang akan salah parameter null or not set.
Ini bisa diterapkan dengan memilih garis yang relevan secara visual, lalu mengetik :. Bilah perintah sudah diisi sebelumnya :'<,'>. Rekatkan perintah di atas dan tekan enter.
Diuji pada versi Vim ini:
VIM -ViIMproved7.3(2010Aug15, compiled Aug22201515:38:58)Compiled by root@apple.com
Pengguna Windows mungkin menginginkan akhir baris yang berbeda.
Menulis fungsi bukanlah ide yang buruk; memohon grepitu buruk. Perhatikan bahwa bashdukungan ${!var_name}sebagai cara untuk mendapatkan nilai dari variabel yang namanya ditentukan $var_name, jadi name=value; value=1; echo ${name} ${!name}hasilkan value 1.
Jonathan Leffler
0
Versi yang lebih pendek untuk menguji variabel yang tidak terdefinisi dapat berupa:
set panggilan tanpa argumen .. output semua vars yang ditentukan ..
yang terakhir dalam daftar akan menjadi yang didefinisikan dalam skrip Anda ..
sehingga Anda dapat menyalurkan outputnya ke sesuatu yang dapat mengetahui hal-hal apa yang didefinisikan dan apa yang tidak
Saya tidak memilih ini, tapi itu adalah godam untuk memecahkan kacang yang agak kecil.
Jonathan Leffler
Saya sebenarnya menyukai jawaban ini lebih baik daripada jawaban yang diterima. Jelas apa yang dilakukan dalam jawaban ini. Jawaban yang diterima tidak masuk akal.
Swiss
Sepertinya jawaban ini lebih merupakan efek samping dari implementasi "set" daripada sesuatu yang diinginkan.
[ -n "${VAR+x}"] && echo not null
[ -z ]
bukan[ -z "" ]
; jika ia memiliki ruang, itu[ -z "my" "test" ]
bukannya[ -z my test ]
; dan jika itu[ -z * ]
, maka*
diganti dengan nama-nama file di direktori Anda.Jawaban:
Saya pikir jawaban Anda setelah tersirat (jika tidak dinyatakan) oleh Vinko 's jawaban , meskipun tidak terbilang sederhana. Untuk membedakan apakah VAR diatur tetapi kosong atau tidak disetel, Anda dapat menggunakan:
Anda mungkin dapat menggabungkan dua tes pada baris kedua menjadi satu dengan:
Namun, jika Anda membaca dokumentasi untuk Autoconf, Anda akan menemukan bahwa mereka tidak merekomendasikan menggabungkan istilah dengan '
-a
' dan merekomendasikan menggunakan tes sederhana terpisah dikombinasikan dengan&&
. Saya belum menemukan sistem di mana ada masalah; itu tidak berarti mereka tidak pernah ada (tetapi mereka mungkin sangat langka hari ini, bahkan jika mereka tidak langka di masa lalu).Anda dapat menemukan detailnya, dan ekspansi parameter shell terkait lainnya ,
test
atau[
perintah dan ekspresi kondisional dalam manual Bash.Baru-baru ini saya ditanya melalui email tentang jawaban ini dengan pertanyaan:
Pertanyaan wajar - jawabannya adalah 'Tidak, alternatif Anda yang lebih sederhana tidak melakukan hal yang sama'.
Misalkan saya menulis ini sebelum ujian Anda:
Tes Anda akan mengatakan "VAR tidak disetel sama sekali", tetapi tes saya akan mengatakan (dengan implikasi karena tidak menggemakan apa pun) "VAR diatur tetapi nilainya mungkin kosong". Coba skrip ini:
Outputnya adalah:
Dalam pasangan tes kedua, variabel diatur, tetapi diatur ke nilai kosong. Ini adalah perbedaan yang dibuat oleh
${VAR=value}
dan${VAR:=value}
notasi. Ditto untuk${VAR-value}
dan${VAR:-value}
, dan${VAR+value}
dan${VAR:+value}
, dan seterusnya.Sebagai Gili menunjukkan dalam bukunya jawaban , jika Anda menjalankan
bash
denganset -o nounset
pilihan, maka jawaban dasar di atas gagal denganunbound variable
. Itu mudah diatasi:Atau Anda dapat membatalkan
set -o nounset
opsi denganset +u
(set -u
setara denganset -o nounset
).sumber
${+}
dan${-}
tidak jelas, tetapi keakraban dengan konstruksi itu sangat penting jika seseorang ingin menjadi pengguna shell yang kompeten.set -o nounset
diaktifkan.[ -v VAR ]
" pendekatan dengan pesta -s v4.2 dan di luar .-z berfungsi untuk variabel yang tidak terdefinisi juga. Untuk membedakan antara yang tidak terdefinisi dan yang didefinisikan, Anda akan menggunakan hal-hal yang tercantum di sini atau, dengan penjelasan yang lebih jelas, di sini .
Cara terbersih adalah menggunakan ekspansi seperti dalam contoh-contoh ini. Untuk mendapatkan semua opsi Anda, periksa bagian Ekspansi Parameter dari manual.
Kata alternatif:
Nilai default:
Tentu saja Anda akan menggunakan salah satu dari ini secara berbeda, menempatkan nilai yang Anda inginkan daripada 'nilai default' dan menggunakan ekspansi secara langsung, jika sesuai.
sumber
Panduan skrip bash tingkat lanjut, 10.2. Substitusi Parameter:
untuk mendasarkan logika program Anda pada apakah variabel $ mystr didefinisikan atau tidak, Anda dapat melakukan hal berikut:
sekarang, jika isdefined = 0 maka variabel tidak terdefinisi, jika isdefined = 1 variabel didefinisikan
Cara memeriksa variabel ini lebih baik daripada jawaban di atas karena lebih elegan, mudah dibaca, dan jika bash shell Anda dikonfigurasi untuk kesalahan pada penggunaan variabel yang tidak ditentukan
(set -u)
, skrip akan berakhir sebelum waktunya.Hal berguna lainnya:
untuk memiliki nilai default 7 ditugaskan ke $ mystr jika itu tidak terdefinisi, dan biarkan utuh jika tidak:
untuk mencetak pesan kesalahan dan keluar dari fungsi jika variabel tidak terdefinisi:
Berhati-hatilah di sini bahwa saya menggunakan ':' agar tidak memiliki isi $ mystr dieksekusi sebagai perintah jika itu didefinisikan.
sumber
var= ; varname=var ; : ${!varname?not defined}
dan ini berakhir:varname=var ; : ${!varname?not defined}
. Tetapi itu adalah kebiasaan yang baik untuk digunakanset -u
yang melakukan hal yang sama lebih mudah.Ringkasan tes.
sumber
${var+x}
itu tidak perlu kecuali jika nama variabel diperbolehkan memiliki ruang di dalamnya.[
untuk mendapatkan hasil yang benar. Jikavar
tidak disetel atau kosong,[ -n $var ]
kurangi[ -n ]
yang memiliki status keluar 0, sementara[ -n "$var" ]
memiliki status keluar yang diharapkan (dan benar) dari 1.https://stackoverflow.com/a/9824943/14731 berisi jawaban yang lebih baik (jawaban yang lebih mudah dibaca dan berfungsi dengan
set -o nounset
diaktifkan). Ini kira-kira berfungsi seperti ini:sumber
Cara eksplisit untuk memeriksa variabel yang didefinisikan adalah:
sumber
test
operator di ujung ekor bagian Bourne Shell Builtins . Saya tidak tahu kapan itu ditambahkan, tetapi tidak dalam versi Applebash
(berdasarkanbash
3.2.51), jadi mungkin fitur 4.x.GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
. Kesalahannya adalah-bash: [: -v: unary operator expected
. Per komentar di sini , membutuhkan minimal 4.2 bash untuk bekerja.pilihan lain: ekspansi "daftar indeks daftar" :
satu-satunya saat ini berkembang ke string kosong adalah ketika
foo
tidak disetel, sehingga Anda dapat memeriksanya dengan string bersyarat:harus tersedia dalam versi bash apa pun> = 3.0
sumber
bukan untuk menumpahkan motor ini lebih jauh, tetapi ingin menambahkan
adalah sesuatu yang dapat Anda tambahkan ke bagian atas skrip, yang akan kesalahan jika variabel tidak dideklarasikan di mana pun dalam skrip. Pesan yang Anda lihat adalah
unbound variable
, tetapi seperti yang disebutkan orang lain, pesan itu tidak akan menangkap string kosong atau nilai nol. Untuk memastikan nilai individual apa pun tidak kosong, kami dapat menguji variabel yang diperluas dengan${mystr:?}
, juga dikenal sebagai ekspansi tanda dolar, yang akan salahparameter null or not set
.sumber
The manual Bash Reference merupakan sumber otoritatif informasi tentang bash.
Berikut adalah contoh pengujian suatu variabel untuk melihat apakah ada:
(Dari bagian 6.3.2 .)
Perhatikan bahwa spasi putih setelah terbuka
[
dan sebelum]
itu tidak opsional .Kiat untuk pengguna Vim
Saya memiliki skrip yang memiliki beberapa deklarasi sebagai berikut:
Tetapi saya ingin mereka tunduk pada nilai-nilai yang ada. Jadi saya menulis ulang mereka agar terlihat seperti ini:
Saya dapat mengotomatisasi ini dalam vim menggunakan regex cepat:
Ini bisa diterapkan dengan memilih garis yang relevan secara visual, lalu mengetik
:
. Bilah perintah sudah diisi sebelumnya:'<,'>
. Rekatkan perintah di atas dan tekan enter.Diuji pada versi Vim ini:
Pengguna Windows mungkin menginginkan akhir baris yang berbeda.
sumber
Inilah yang menurut saya merupakan cara yang jauh lebih jelas untuk memeriksa apakah suatu variabel didefinisikan:
Gunakan sebagai berikut:
sumber
grep
itu buruk. Perhatikan bahwabash
dukungan${!var_name}
sebagai cara untuk mendapatkan nilai dari variabel yang namanya ditentukan$var_name
, jadiname=value; value=1; echo ${name} ${!name}
hasilkanvalue 1
.Versi yang lebih pendek untuk menguji variabel yang tidak terdefinisi dapat berupa:
sumber
set panggilan tanpa argumen .. output semua vars yang ditentukan ..
yang terakhir dalam daftar akan menjadi yang didefinisikan dalam skrip Anda ..
sehingga Anda dapat menyalurkan outputnya ke sesuatu yang dapat mengetahui hal-hal apa yang didefinisikan dan apa yang tidak
sumber