Bagaimana cara saya memeriksa apakah ada variabel dalam pernyataan 'jika'?

69

Saya perlu memeriksa keberadaan variabel dalam sebuah ifpernyataan. Sesuatu untuk efek:

if [ -v $somevar ]
then
    echo "Variable somevar exists!"
else
    echo "Variable somevar does not exist!"

Dan pertanyaan terdekatnya adalah ini , yang sebenarnya tidak menjawab pertanyaan saya.

Menarik...
sumber
Jika Anda ingin mengatur $somevarke nilai / string jika variabel tidak ada: ${somevar:=42}.
Cyrus
Secara pribadi, saya cenderung memeriksa hanya untuk kekosongan ( [ -n "$var" ]atau [ ! -z "$var" ]). Saya pikir pemeriksaan keberadaan / tidak ada terlalu halus, dan saya lebih suka kode saya kasar dan sederhana.
PSkocik
Mengapa Anda membutuhkan itu vs [ -n "$var" ]? Terkait: stackoverflow.com/questions/3601515/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Jawaban:

97

Dalam bash modern (versi 4.2 dan di atasnya):

[[ -v name_of_var ]]

Dari help test:

-v VAR, Benar jika variabel shell VAR diatur

Chris Down
sumber
3
Juga bekerja dengan kurung tunggal: [ -v name_of_var ].
meuh
7
Waspadalah bahwa untuk hash dan array, ia mengembalikan false kecuali variabel memiliki elemen kunci / indice "0". Untuk namerefs, ia menguji apakah target didefinisikan. Ini tidak bekerja untuk parameter khusus seperti $1, $-, $#...
Stéphane Chazelas
4
Fitur ini hanya ada di bash builtin testatau [; Ini tidak tersedia di /usr/bin/test. Bandingkan man testdengan help test.
Mark Lakata
@ MarkLakata Benar, karena perintah eksternal tidak dapat mengetahui keadaan internal shell.
Chris Down
umm bukankah seharusnya selalu [[-v "$ name_of_var"]]?
Alexander Mills
24

Tergantung apa yang Anda maksud dengan yang ada .

Apakah variabel yang telah dideklarasikan tetapi tidak ditugaskan ada ?

Apakah variabel array (atau hash) yang telah ditetapkan daftar kosong ada ?

Apakah variabel nameref menunjuk ke variabel yang saat ini tidak ditetapkan ada ?

Apakah Anda menganggap $-, $#, $1variabel? (POSIX tidak).

Dalam cangkang mirip Bourne, cara kanonik adalah:

if [ -n "${var+set}" ]; then
  echo '$var was set'
fi

Itu berfungsi untuk variabel skalar dan parameter lain untuk mengetahui apakah suatu variabel telah diberi nilai (kosong atau tidak, secara otomatis, dari lingkungan, tugas read, foratau lainnya).

Untuk shell yang memiliki perintah typesetatau declare, yang tidak akan melaporkan set variabel yang telah dideklarasikan tetapi tidak ditugaskan kecuali di zsh.

Untuk shell yang mendukung array, kecuali yashdan zshyang tidak akan dilaporkan sebagai variabel array set kecuali elemen indice 0 telah ditetapkan.

Untuk bash(tetapi tidak ksh93juga zsh), untuk variabel array asosiatif tipe , itu tidak akan melaporkannya sebagai set kecuali elemen mereka dari kunci "0" telah ditetapkan.

Untuk ksh93dan bash, untuk variabel tipe nameref , itu hanya mengembalikan true jika variabel yang direferensikan oleh nameref itu sendiri dianggap ditetapkan .

Untuk ksh, zshdan bash, pendekatan yang berpotensi lebih baik adalah:

if ((${#var[@]})); then
  echo '$var (or the variable it references for namerefs) or any of its elements for array/hashes has been set'
fi

Untuk ksh93, zshdan bash4.4 atau lebih, ada juga:

if typeset -p var 2> /dev/null | grep -q '^'; then
  echo '$var exists'
fi

Yang akan melaporkan variabel yang telah ditetapkan atau dideklarasikan.

Stéphane Chazelas
sumber
1
declare -pSaya typeset -pbekerja di bashsekarang juga.
cas
1
@Nomer CAS. Bukan untuk menyatakan tetapi tidak mengatur variabel. Coba bash -c 'typeset -i a; typeset -p a'dan bandingkan dengan ksh93atau zsh.
Stéphane Chazelas
+1 Terima kasih atas poin saya di sini. Lihat juga pertanyaan saya unix.stackexchange.com/q/280893/674
Tim
@cas, yang berubah dengan bash-4.4 (dirilis pada September 2016), saya telah mengeditnya di.
Stéphane Chazelas
9

Seperti yang disebutkan dalam jawaban pada SO , berikut adalah cara untuk memeriksa:

if [ -z ${somevar+x} ]; then echo "somevar is unset"; else echo "somevar is set to '$somevar'"; fi

di mana $ {somevar + x} adalah ekspansi parameter yang mengevaluasi ke nol jika var tidak disetel dan menggantikan string "x" sebaliknya.

Menggunakan -n, seperti yang disarankan oleh jawaban lain, hanya akan memeriksa apakah variabel berisi string kosong. Itu tidak akan memeriksa keberadaannya.

shivams
sumber
2
Anda perlu mengutip $somevaruntuk menangani IFS=x. Entah itu atau mengutip x.
mikeserv
1
@ mikeserv Terima kasih, saya suka belajar tentang kasus tepi :) Maksud Anda if [ -z "${somevar+x}" ]? Apakah kutipan masih diperlukan di dalam [[dan ]]?
Tom Hale
@ TomHale - ya, dalam kasus yang jarang terjadi. yang [ testrutin menerima parameter baris perintah, sehingga ekspansi biasa dan interpretasi seperti yang diperintahkan dalam cara yang biasa harus diandalkan untuk membuat di doa dari tes yang diterapkan apa yang harus Anda menyebabkan untuk dibaca demikian oleh setiap baris perintah program yang. test {! + "!"}
mikeserv
@ mikeserv Saya kira ya Anda untuk pertanyaan 2 saya ... Apakah yang pertama ya juga?
Tom Hale
1
+1; ini tampaknya menjadi cara paling sederhana untuk melakukan ini ketika set -usedang berlaku dan versi Bash adalah pra-4.2.
Kyle Strand
4

POSIXly:

! (: "${somevar?}") 2>/dev/null && echo somevar unset

atau Anda dapat membiarkan shell Anda menampilkan pesan untuk Anda:

(: "${somevar?}")
zsh: somevar: parameter not set
cuonglm
sumber
@ mikeserv: Ya, tentu saja, ada banyak cara untuk melakukannya. Pertama, saya pikir saya akan menggandakannya dengan ini . Tetapi dalam pertanyaan ini, OP hanya ingin memeriksa, dia tidak mengklaim bahwa dia ingin keluar atau melaporkan jika variabel tidak disetel, jadi saya datang dengan cek dalam subkulit.
cuonglm
2
Yah, saya tahu, tapi itu justru karena Anda harus melakukannya dalam subshell seperti itu yang menunjukkan itu mungkin bukan cara terbaik untuk menguji di sini - itu adalah tindakan penghentian kegagalan, itu tidak memungkinkan untuk cara sederhana untuk menangani sebuah kegagalan. Portabl bahkan traphanya dapat bekerja pada EXIT. Itu yang saya katakan - itu hanya tidak berlaku sebagai lulus / gagal dengan sangat baik. Dan ini juga bukan saya yang berbicara - saya sudah melakukan ini sebelumnya dan butuh sedikit komentar obrolan seperti ini untuk meyakinkan saya. Jadi, saya pikir saya akan membayarnya.
mikeserv
1
@ mikeserv: Yah, well, itu poin yang bagus. Saya hanya ingin tahu, apakah menambahkan itu dapat membuat OP bingung dengan sintaksnya :)
cuonglm
2
if set|grep '^somevar=' >/dev/null;then
    echo "somevar exists"
else
    echo "does not exist"
fi
Mel
sumber
Saya membayangkan ini agak tidak efisien, tetapi sangat sederhana dan shkompatibel, yang memang saya butuhkan.
hoijui
2
printf ${var+'$var exists!\n'}

... tidak akan mencetak apa pun ketika tidak ada. Atau...

printf $"var does%${var+.}s exist%c\n" \ not !

... akan memberitahumu juga.

Anda dapat menggunakan nilai pengembalian tes untuk secara dinamis memperluas ke string format yang sesuai untuk kondisi Anda:

[ "${var+1}" ]
printf $"var does%.$?0s exist%c\n" \ not !

Anda juga dapat membuat printfkegagalan berdasarkan substitusi ...

printf $"var does%${var+.}s exist%c\n%.${var+b}d" \
        \ not ! \\c >&"$((2${var+-1}))" 2>/dev/null

... yang mencetak $var does not exist!ke stderr dan mengembalikan selain 0 ketika $vartidak disetel, tetapi mencetak $var does exist!ke stdout dan mengembalikan 0 saat $vardiatur.

mikeserv
sumber
1

Baris sederhana ini berfungsi (dan bekerja pada sebagian besar shell POSIX):

${var+"false"} && echo "var is unset"

Atau, ditulis dalam bentuk yang lebih panjang:

unset var

if ${var+"false"}
then
   echo "var is unset"
fi

Ekspansi adalah:

  • Jika var memiliki nilai (bahkan nol), false diganti
  • Jika var memiliki "tidak ada nilai", maka "tidak ada nilai" (nol) diganti.

The ${var+"false"}ekspansi memperluas baik "nol" dari "false".
Kemudian, "tidak ada" atau "salah" dijalankan, dan kode keluar ditetapkan.

Tidak perlu memanggil perintah test( [atau [[) karena nilai keluar diatur oleh (pelaksanaan) ekspansi itu sendiri.


sumber
Ya, kecuali dalam beberapa versi lama zsh in shulation ketika $IFSberisi f, a, l, s atau e. Seperti untuk jawaban lain, ada kasus array, hash, atau jenis variabel lain yang mungkin ingin disebutkan.
Stéphane Chazelas
@ StéphaneChazelas saya tulis most POSIX shells. most artinyaIn the greatest number of instances tidak semua. ... ... Jadi, ya, dalam kondisi yang tidak jelas when $IFS contains f, a, l, s or edan untuk beberapa shell yang tidak jelas some old versions of zshini gagal: Sungguh mengejutkan !. Saya harus berasumsi bahwa bug tersebut telah dipecahkan sejak lama. ... ... Apakah Anda mengusulkan agar kami harus menulis kode untuk kerang yang sudah lama rusak ?.
@ StéphaneChazelas Juga: Judul pertanyaan sangat spesifik: Bash.
zebra biner ???
mikeserv
0

Cara shell murni:

[ "${var+1}" ] || echo "The variable has not been set"

Skrip uji:

#!/bin/sh
echo "Test 1, var has not yet been created"
[ "${var+1}" ] || echo "The variable has not been set"

echo "Test 2, var=1"
var=1
[ "${var+1}" ] || echo "The variable has not been set"

echo "Test 3, var="
var=
[ "${var+1}" ] || echo "The variable has not been set"

echo "Test 4, unset var"
unset var
[ "${var+1}" ] || echo "The variable has not been set"
echo "Done"

Hasil:

Test 1, var has not yet been created
The variable has not been set
Test 2, var=1
Test 3, var=
Test 4, unset var
The variable has not been set
Done
Bank Andreas Mikael
sumber
1
Gagal saat variabel disetel ke string nol.
Tom Hale
0

Dengan bash 4.4.19 berikut ini bekerja untuk saya. Ini adalah contoh lengkapnya

$export MAGENTO_DB_HOST="anyvalue"

#!/bin/bash

if [ -z "$MAGENTO_DB_HOST" ]; then
    echo "Magento variable not set"
else
    echo $MAGENTO_DB_HOST
fi
Aftab Naveed
sumber
-1

Anda tidak dapat menggunakan ifperintah untuk memeriksa keberadaan variabel yang dideklarasikan dalam bash namun -vopsi ada di bash yang lebih baru, tetapi tidak portabel dan Anda tidak dapat menggunakannya dalam bashversi yang lebih lama . Karena ketika Anda menggunakan variabel jika tidak ada itu akan lahir pada saat yang sama.

Misalnya Bayangkan bahwa saya tidak menggunakan atau menetapkan nilai ke MYTESTvariabel, tetapi ketika Anda menggunakan perintah gema itu tidak menunjukkan apa-apa! Atau jika Anda menggunakannya if [ -z $MYTEST ]mengembalikan nilai nol! Itu tidak mengembalikan status keluar lain, yang memberitahu Anda bahwa variabel ini tidak ada!

Sekarang Anda memiliki dua solusi (Tanpa -vopsi):

  1. Menggunakan declareperintah.
  2. Menggunakan setperintah.

Sebagai contoh:

MYTEST=2
set | grep MYTEST
declare | grep MYTEST

Namun sayangnya perintah ini menunjukkan Anda memuat fungsi dalam memori juga! Anda dapat menggunakan declare -p | grep -q MYTEST ; echo $?perintah untuk hasil yang lebih bersih.

Sepahrad Salour
sumber
-1

Berfungsi untuk memeriksa apakah variabel dinyatakan / tidak disetel

termasuk kosong $array=()


Selain jawaban @ Gilles

case " ${!foobar*} " in
  *" foobar "*) echo "foobar is declared";;
  *) echo "foobar is not declared";;
esac

- yang saya tidak menemukan cara untuk untuk merangkum itu dalam fungsi - Saya ingin menambahkan versi sederhana, yang sebagian didasarkan pada Richard Hansen 's jawaban , tetapi tidak alamat juga perangkap yang terjadi dengan kosong array=():

# The first parameter needs to be the name of the variable to be checked.
# (See example below)

var_is_declared() {
    { [[ -n ${!1+anything} ]] || declare -p $1 &>/dev/null;}
}

var_is_unset() {
    { [[ -z ${!1+anything} ]] && ! declare -p $1 &>/dev/null;} 
}
  • Dengan pengujian pertama jika variabel diatur (tidak), panggilan untuk mendeklarasikan dapat dihindari, jika tidak perlu.
  • Namun jika $1berisi nama yang kosong $array=(), panggilan untuk menyatakan akan memastikan kami mendapatkan hasil yang benar
  • Tidak pernah ada banyak data yang dikirimkan ke / dev / null karena menyatakan hanya dipanggil jika variabel tidak disetel atau array kosong.


Dengan kode berikut fungsinya dapat diuji:

( # start a subshell to encapsulate functions/vars for easy copy-paste into the terminal
  # do not use this extra parenthesis () in a script!

var_is_declared() {
    { [[ -n ${!1+anything} ]] || declare -p $1 &>/dev/null;}
}

var_is_unset() {
    { [[ -z ${!1+anything} ]] && ! declare -p $1 &>/dev/null;} 
}

:;       echo -n 'a;       '; var_is_declared a && echo "# is declared" || echo "# is not declared"
a=;      echo -n 'a=;      '; var_is_declared a && echo "# is declared" || echo "# is not declared"
a="sd";  echo -n 'a="sd";  '; var_is_declared a && echo "# is declared" || echo "# is not declared"
a=();    echo -n 'a=();    '; var_is_declared a && echo "# is declared" || echo "# is not declared"
a=("");  echo -n 'a=("");  '; var_is_declared a && echo "# is declared" || echo "# is not declared"
unset a; echo -n 'unset a; '; var_is_declared a && echo "# is declared" || echo "# is not declared"
echo ;
:;       echo -n 'a;       '; var_is_unset a && echo "# is unset" || echo "# is not unset"
a=;      echo -n 'a=;      '; var_is_unset a && echo "# is unset" || echo "# is not unset"
a="foo"; echo -n 'a="foo"; '; var_is_unset a && echo "# is unset" || echo "# is not unset"
a=();    echo -n 'a=();    '; var_is_unset a && echo "# is unset" || echo "# is not unset"
a=("");  echo -n 'a=("");  '; var_is_unset a && echo "# is unset" || echo "# is not unset"
unset a; echo -n 'unset a; '; var_is_unset a && echo "# is unset" || echo "# is not unset"
)

Script harus dikembalikan

a;       # is not declared
a=;      # is declared
a="foo"; # is declared
a=();    # is declared
a=("");  # is declared
unset a; # is not declared

a;       # is unset
a=;      # is not unset
a="foo"; # is not unset
a=();    # is not unset
a=("");  # is not unset
unset a; # is unset
Martin Rüegg
sumber
-1

fungsi bash yang berfungsi untuk tipe skalar dan array :

definisi

has_declare() { # check if variable is set at all
    local "$@" # inject 'name' argument in local scope
    &>/dev/null declare -p "$name" # return 0 when var is present
}

doa

if has_declare name="vars_name" ; then
   echo "variable present: vars_name=$vars_name"
fi
Andrei Pozolotin
sumber