Bir değişkenin 'if' ifadesinde olup olmadığını nasıl kontrol ederim?


69

Bir değişkenin varlığını bir ififadede kontrol etmem gerekiyor . Etkisi için bir şey:

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

Ve bu en yakın soru bu aslında benim soruya cevap vermez, hangi.


Eğer ayarlamak isterseniz $somevarbir değer / dizeye değişken yoksa: ${somevar:=42}.
Cyrus

Şahsen ben sadece boşluk ( [ -n "$var" ]veya [ ! -z "$var" ]) olup olmadığını kontrol etmek eğilimindedir . Varlık / yokluk kontrollerinin çok ince olduğunu düşünüyorum ve kodumun kaba ve basit olmasını tercih ediyorum.
PSkocik

Yanıtlar:


97

Modern bash'ta (sürüm 4.2 ve üstü):

[[ -v name_of_var ]]

Kimden help test:

-v VAR, VAR kabuk değişkeni ayarlandıysa True


3
Ayrıca tek parantez çalışır: [ -v name_of_var ].
meuh

7
karma ve diziler için değişken, "0" anahtar / indis elemanına sahip değilse, false döndürür. Namerefs için hedefin tanımlanıp tanımlanmadığını test eder. Bu gibi özel parametreler için çalışmıyor $1, $-, $#...
Stéphane Chazelas

4
Bu özellik yalnızca bash yerleşkesinde testya da [; İçinde mevcut değil /usr/bin/test. Karşılaştırma man testile help test.
Mark Lakata

@MarkLakata Doğru, çünkü harici komutlar kabuğun iç durumunu bilemez.
Chris Down

umm her zaman [[-v "$ name_of_var"]] olmamalı mıydı?
Alexander Mills,

24

Derken ne demek istediğine bağlı bulunmaktadır .

Beyan edilmiş fakat atanmamış bir değişken var mı?

Boş bir liste atanmış bir dizi (ya da karma) değişkeni var mı?

Şu anda atanmamış bir değişkeni işaret eden bir aderef değişkeni var mı?

Dikkate musunuz $-, $#, $1değişkenler? (POSIX yapmaz).

Bourne benzeri mermilerde kanonik yol şudur:

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

Yani (atamaları, otomatik, boş ya da değil, çevreden değişken bir değeri atanmıştır anlamanın skaler değişkenler ve diğer parametreler için çalışır read, forveya başka).

Bir var gövdeler için typesetya declarekadar komutu, rapor olmaz ayarlanmış olan değişkenler beyan fakat atanan hariç zsh.

Dizileri destekleyen kabukları için, dışında yashve 0 dizininin öğesi ayarlanmadıkça, dizi dizisi değişkenleri olarak zshbildirilmeyen raporlar .

İçin bash(ama ksh93ne de değil zsh), ilişkisel dizi türündeki değişkenler için , "0" anahtar öğeleri belirlenmemişse , bunları ayarlanmış olarak bildirmez .

İçin ksh93ve bash, tipi değişkenler için nameref , o tek gerçek döndüren nameref tarafından başvurulan değişken kendisi kabul ise set .

İçin ksh, zshve bashpotansiyel olarak daha iyi bir yaklaşım olabilir:

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

İçin ksh93, zshve bash4.4 veya üzeri, orada da:

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

Belirlenmiş veya bildirilmiş değişkenleri bildirecektir.


1
declare -p/ şimdi de typeset -pçalışıyor bash.
cas,

1
@CAS Numarası. Beyan edilenler için değil, değişkenler için. Veya bash -c 'typeset -i a; typeset -p a'ile karşılaştırmayı deneyin . ksh93zsh
Stéphane Chazelas

+1 Beni burada gösterdiğiniz için teşekkür ederiz. Ayrıca soruma
Tim

bash-4.4 ile değiştirilen @cas (Eylül 2016'da yayımlandı), bunu düzenlemişim.
Stéphane Chazelas

9

SO cevabında da belirtildiği gibi, kontrol etmenin bir yolu:

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

burada $ {somevar + x} var ayarlanmamışsa null değerine sahip olan ve aksi takdirde "x" dizesini değiştiren bir parametre genişletmesidir.

-nDiğer cevabın önerdiği gibi kullanılması sadece değişkenin boş dize içerip içermediğini kontrol edecektir. Varlığını kontrol etmeyecek.


2
Sen alıntı gerek $somevarişlemek için IFS=x. Ya öyle ya da alıntı x.
mikeserv

1
@mikeserv sayesinde, uç örnekleri görmeyi seviyorum :) Şunu musunuz if [ -z "${somevar+x}" ]? Alıntı hala içinde [[ve içinde gerekli ]]midir?
Tom Hale

@ TomHale - evet, nadir durumlarda. [ testTestin çağrı sırasında işlemek için bağlı olunmaması gereken normal şekilde sipariş herhangi bir program komut satırı ile suretle okunmasına neden gereken o uygulamalı olarak rutinleri komut satırı parametreleri ve böylece her zamanki açılımlar ve yorumlara kabul ediyoruz. test {! + "!"}
mikeserv

@mikeserv Sanırım evet, benim ikinci sorum, ... Birincisi de evet mi?
Tom Hale

1
+ 1; Bu set -u, etkin olduğunda ve Bash sürümü 4.2 öncesiyken bunu yapmanın en basit yolu gibi görünmektedir .
Kyle Strand,

4

POSIXly:

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

veya kabuğunuzun sizin için mesajı göstermesine izin verebilirsiniz:

(: "${somevar?}")
zsh: somevar: parameter not set

@mikeserv: Evet, elbette, yapmanın birçok yolu var. Öncelikle, ben bunu çoğaltılır olacağını düşünüyorum bu . Fakat bu soruya, OP sadece kontrol etmek istiyor, değişken ayarlanmadığında çıkış yapmak veya rapor etmek istediğini iddia etmiyordu, bu yüzden alt kabukta bir kontrol ile geldim.
cuonglm

2
Şey, biliyorum, ama kesin olarak, bunu test etmenin en iyi yolu olmayacağını gösteren bir kabukta yapmak zorunda olduğunuz için - bu başarısızlıkta durma hareketidir, herhangi bir basit yolla başa çıkmasına izin vermez başarısızlık. Taşınabilir bir bile trapsadece EXIT üzerinde çalışabilir. Tüm söylediğim bu - çok iyi bir pas / başarısız olarak geçerli değil. Ve bu da benim konuşmam değil - bunu daha önce de yaptım ve beni ikna etmek için böyle bir yorum sohbeti yaptım. Ben de ödediğimi düşündüm.
mikeserv

1
@mikeserv: Güzel, bu iyi bir nokta. Sadece merak ediyorum, eklenmesi OP'nin sözdizimi ile karıştırılmasını sağlayabilir mi :)
cuonglm

2
if set|grep '^somevar=' >/dev/null;then
    echo "somevar exists"
else
    echo "does not exist"
fi

Bunun biraz verimsiz olduğunu hayal ediyorum, ama çok basit ve shuyumlu, bu da tam ihtiyacım olan şey.
hoijui,

2
printf ${var+'$var exists!\n'}

... olmadığında hiçbir şey basmayacak. Veya...

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

... her iki şekilde de söyleyeceğim.

durumunuza uygun format dizgisine dinamik olarak genişletmek için bir testin dönüş değerini kullanabilirsiniz:

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

Ayrıca printfbir oyuncu değişikliği durumuna göre başarısız yapabilirsiniz ...

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

... $var does not exist!stderr basar ve $varayarlanmadığında 0 dışında döndürür , ancak $var does exist!stdout'a basar ve $varayarlandığı zaman 0 döndürür .


1

Bu basit çizgi çalışır (ve çoğu POSIX mermisinde çalışır):

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

Veya daha uzun bir biçimde yazılmış:

unset var

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

Genişleme:

  • Var bir değere sahipse (hatta null), false değiştirilir
  • Var "değer yok" ise, "değer yok" (boş) değiştirilir.

${var+"false"}Genişleme "false" ya "boş" genişler.
Ardından, "hiçbir şey" veya "yanlış" yürütülür ve çıkış kodu ayarlanır.

Çıkış değeri, genişlemenin kendisi tarafından yürütülürken ayarlandığı için test( [veya [[) komutunu çağırmaya gerek yoktur .


Evet, $IFSf, a, l, s veya e içerdiğinde shsh emülasyonunda bazı eski zsh sürümleri dışında . Diğer cevaplar gibi, bunlardan bahsetmek isteyebileceğiniz diziler, karmalar veya diğer değişken türleri söz konusudur.
Stéphane Chazelas

@ StéphaneChazelas yazdım most POSIX shells. hepsi değil most demektirIn the greatest number of instances . ... ... Yani, evet, belirsiz bir durumda when $IFS contains f, a, l, s or eve bazı belirsiz bir kabuk için some old versions of zshbu başarısız: Ne şok! Böyle bir hatanın uzun zaman önce çözüldüğünü varsaymalıyım. ... ... uzun zaman önce kırılmış mermiler için kod yazmamızı mı öneriyorsun?

@ StéphaneChazelas Ayrıca: Soru başlığı çok özeldir: Bash.

ikili zebra ???
mikeserv

0

Saf kabuk yolu:

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

Test komut dosyası:

#!/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"

Sonuçlar:

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

1
Değişken null dizeye ayarlandığında başarısız olur.
Tom Hale,

0

Bash 4.4.19 ile aşağıdaki benim için çalıştı. İşte tam bir örnek

$export MAGENTO_DB_HOST="anyvalue"

#!/bin/bash

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

-1

ifBash'ta bildirilen değişkenlerin varlığını kontrol etmek için komutu kullanamazsınız , ancak -vseçenek daha yeni bash'ta bulunur, ancak taşınabilir değildir ve eski bashsürümlerde kullanamazsınız . Çünkü eğer bir değişken kullanıyorsanız, yoksa aynı anda doğacaktır.

Örneğin, MYTESTdeğişkene bir değer kullanmadığımı veya bir değer atamadığımı hayal edin , ancak echo komutunu kullanırken size hiçbir şey göstermediğini! Ya da kullanıyorsanız if [ -z $MYTEST ]sıfır değeri döndürdü! Başka bir çıkış durumu döndürmedi, bu da size bu değişkenin bulunmadığını söyler!

Şimdi iki -vseçeneğiniz var (seçeneksiz ):

  1. declareKomutunu kullanarak .
  2. setKomutunu kullanarak .

Örneğin:

MYTEST=2
set | grep MYTEST
declare | grep MYTEST

Fakat ne yazık ki bu komutlar, hafızaya yüklediğiniz fonksiyonları da gösterir! declare -p | grep -q MYTEST ; echo $?Temiz sonuç için komutu kullanabilirsiniz .


-1

Değişken bildirilip işaretlenmediğini kontrol etme işlevi

boş dahil $array=()


@ Gilles'in cevabına ek olarak

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

- Ben bir işlev içinde hapsetmek için bir yol bulamadık hangi - Ben kısmen dayanan basit bir versiyonunu, eklemek istediğiniz Richard Hansen 'in cevabı , ancak adresini boş ile oluşur de hatadır yapar 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;} 
}
  • İlk önce değişken (un) ayarlanmışsa test ederek, bildirmek için yapılan çağrıdan, gerekli değilse önlenebilir.
  • Ancak $1boş bir ad içeriyorsa, $array=()bildirilecek çağrı doğru sonucu aldığımızdan emin olacaktır.
  • / Dev / null öğesine iletilen hiçbir zaman çok veri yoktur, çünkü beyan yalnızca değişken değişken ayarlanmadığında veya boş bir dizi olduğunda çağrılır.


Aşağıdaki kod ile fonksiyonlar test edilebilir:

( # 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 dönmeli

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

-1

skalar ve dizi türleri için çalışan bash işlevi :

tanım

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
}

yakarma

if has_declare name="vars_name" ; then
   echo "variable present: vars_name=$vars_name"
fi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.