Birden çok değişkenin ayarlanıp ayarlanmadığını test edin


19

Bir komut dosyasının belirli bir noktasında source, bir yapılandırma dosyası girdikten sonra , birkaç değişkenin ayarlandığından ve yürütülmediyse, kullanıcıya eksik değişken hakkında bilgi verdiğinden emin olmak istiyorum. denedim

for var in $one $two $three ; do
    ...

ancak örneğin $twoayarlanmazsa, döngü hiçbir zaman çalıştırılmaz $two. Bir sonraki denediğim şey

for var in one two three ; do
    if [ -n ${!var} ] ; then
        echo "$var is set to ${!var}"
    else
        echo "$var is not set"
    fi
done

Ama iki ayarlanmadıysa, hala "iki ayarlanmadı" yerine "iki ayarlandı" alıyorum.

Gerekli tüm değişkenlerin ayarlandığından nasıl emin olabilirim?

Güncelleme / Çözüm: "set" ve "set ama boş" arasında bir fark olduğunu biliyorum. Şimdi ( /programming//a/16753536/3456281 ve bu sorunun cevapları sayesinde ) aşağıdakileri kullanıyorum:

if [ -n "${!var:-}" ] ; then

Bu nedenle, varayarlanmış ancak boşsa, yine de geçersiz kabul edilir.


1
Ayrıca set -u, ayarlanmamış bir değişken kullanıldığında komut dosyasını hemen sonlandırmak için komut dosyanızın başına ekleyebilirsiniz .
n.st

Yanıtlar:


8

Alıntılama hatası.

if [ -n "${!var}" ] ; then

Gelecek için: Ayar

set -x

kodu çalıştırmadan önce size sorunu gösterecektir. Bunu koda eklemek yerine komut dosyanızı

bash -vx ./my/script.sh

Bu işe yarar, ama / whithout alıntılarıyla neler oluyor? Genel yaklaşımım ilk etapta doğru mu?
Jasper

Evet, bu mantıklı: Soruyu sorulmadan önce cevapladım ... 8-)
Hauke ​​Laging

4
@Jasper Her zaman değişkenleri alıntılamalısınız. Bunun her zaman gerekli olup olmadığını düşünmekten daha fazla zamana mal olmaz. Ancak hataları önler.
Hauke ​​Laging

Aksine, alıntı sadece genişlemeye karşı korur. Genişleme ilgilendiğiniz şeyse, alıntı yapmak kesinlikle doğru yol değildir. Örneğin: cs = 673,290,765; set - $ (IFS =,; echo $ cs); echo $ #; çıkış: 3
mikeserv

2
@mikeserv Açıkçası önermediğim şey, tek tırnak işaretleri genişlemeye karşı koruma sağlar. Çift tırnak sözcük bölünmesine karşı koruma sağlar. Alıntı yapmanın ihmal edilmesi gereken durumlar olabileceğini reddetmedim. Ama bu benim genel kuralıma karşı bir tartışma değil. Ne tür insanlar böyle bir şey kullanacak set -- $(IFS=, ; echo $cs)? Burada sorması gereken insanlar neden if [ -n ${!var} ] ; thençalışmıyor? Muhtemelen değil.
Hauke ​​Laging

5

İhtiyacınız olan tek şey testinizdeki alıntılardır:

for var in one two three ; do
    if [ -n "${!var}" ] ; then
        echo "$var is set to ${!var}"
    else
        echo "$var is not set"
    fi
done

Benim için çalışıyor.


4

Programın durmasını istiyorsanız:

N= 
${one?var 1 is unset} 
${two:?var 2 is unset or null}
${three:+${N:?var 3 is set and not null}}

Hile yapacak. Soru işaretini izleyen mesajların her biri yazdırılır stderrve üst kabuk ölür. Tamam, tamam, değil her mesaj - sadece bir - başarısız olan ilk mesaj kabuğun ölmesine neden olur. Bu testleri şu şekilde kullanmayı seviyorum:

( for v in "$one" "$two" "$three" ; do
    i=$((i+1)) ; : ${v:?var $i is unset or null...} 
done ) || _handle_it

Burada bunun hakkında söyleyecek çok şeyim vardı .


2

Ekleyebilirsin

set -u

ayarlanmamış bir değişken kullanmaya çalıştığında sonlandırılmasını sağlamak için komut dosyanızın başına

Gibi bir senaryo

#!/bin/sh
set -u
echo $foo

sonuçlanacak

script.sh: 3: script.sh: foo: parametre ayarlanmadı

Eğer kullanıyorsanız bashbunun yerine, hata aşağıdaki gibi görünecektir:

script.sh: satır 3: foo: ilişkisiz değişken


Ve sizce bu çalışma süresi kontrolleri için hangi mantıklı?
Hauke ​​Laging

2
@HaukeLaging Seni set -utam olarak takip etmiyorum - OP'nin kaçınmaya çalıştığı hata türünü tam olarak önler ve (diğer tüm çözümlerin aksine) belirli bir değişken seti ile sınırlı değildir. Aslında bir değişken ayarlanmadığında beklenmedik şeyler yapmak yerine neredeyse tüm kabuk betiklerinin güvenli bir şekilde başarısız olması yararlı bir önlemdir. Bu makale konuyla ilgili kullanışlı bir kaynaktır.
n.

@ n.st Ben katılmıyorum - null planlıyorsanız null değeri null değil kadar yararlı olabilir.
mikeserv

1
@ n.st Bu, OP için ayarlanmamış değişkenlere erişime karşı bir koruma istemediğinden bir anlam ifade etmiyor (BTW: bir küme ancak boş bir değişken aynı hataya neden olacak, ancak "korumanıza" tepki vermeyecek). Bir değişkenin ayarlanmamış / boş olup olmadığını kontrol etmek istiyor. Öneriniz genel bir geliştirme yardımı olarak yararlı olabilir, ancak OP'nin sorununu çözmez.
Hauke ​​Laging

set -uBen de kullanılabilir, ancak uygun parametre genişletme kadar esnek değil (güncellenmiş sorum). Ve set -uonların varlığını tek bir yerde kontrol etmek istiyorsam, tüm hedef değişkenlere bir kukla erişim yapmak zorunda kalacaktım.
Jasper

2

Maksimum dostu olan bir çözüm, ilkinde başarısız olmak ve işleri düzeltmek için ileri-geri gitmek yerine tüm gereksinimleri test eder ve bunları birlikte raporlar:

#!/bin/bash

required_vars=(one two three)

missing_vars=()
for i in "${required_vars[@]}"
do
    test -n "${!i:+y}" || missing_vars+=("$i")
done
if [ ${#missing_vars[@]} -ne 0 ]
then
    echo "The following variables are not set, but should be:" >&2
    printf ' %q\n' "${missing_vars[@]}" >&2
    exit 1
fi

Hangi değişkenlerin ayarlanmadığını izlemek için bir dizi değişkeni kullanıyorum ve kullanıcıya dönük bir ileti oluşturmak için sonucu kullanıyorum.

Notlar:

  • Ben alıntılanan ${required_vars[@]}içindefor ağırlıklı olarak alışkanlıktan döngü - Ben senin değişken isimlerinde herhangi kabuk meta dahil tavsiye etmem!
  • Alıntı yapmadım ${#missing_vars[@]} , çünkü önceki tavsiyeyi göz ardı edecek kadar sapkın olsanız bile, bu her zaman bir tamsayıdır.
  • %qYazdırırken kullandım ;%snormalde yeterli olur.
  • Hata çıkışı her zaman şu hata akışına gider: >&2 , bu nedenle aşağı akış komutlarına aktarılmaz
  • Sessizlik altındır - özellikle sorulmadıkça ilerleme bilgilerini veya hata ayıklama bilgilerini yazdırmayın. Bu hataları daha açık hale getirir.

1

bash4.2 bir değişkenin -voperatörle ayarlanıp ayarlanmadığını test etmenizi sağlar ; ayarlanmamış bir değişken ve boş dizeye ayarlanmış bir değişken iki farklı koşuldur:

$ unset foo
$ [[ -v foo ]] && echo foo is set
$ [[ -z "$foo" ]] && echo foo is empty
foo is empty
$ foo=
$ [[ -v foo ]] && echo foo is set
foo is set
$ [[ -z "$foo" ]] && echo foo is empty
foo is empty

"Çoklu" değişkenler hakkında soruyordum, dolaylı olarak dolaylı bir şey arıyordum ...
Jasper

O zamandan beri, indirection gerekmez -valır adını böylece, bir değişkenin for var in one two three; [[ -v $var ]] && ...; doneher olmadığını kontrol ediyorum one, twove threesırayla ayarlanır.
chepner

1

Bence not set, yani değişken asla başlatılmamalıdır. Kullanırsanız [ -n "${!var}" ], böyle boş değişken ayarlanmışkentwo="" başarısız olur . Bunu deneyebilirsiniz:

one=1
three=3

for var in one two three; do
  declare -p $var > /dev/null 2>&1 \
  && printf '%s is set to %s\n' "$var" "${!var}" \
  || printf '%s is not set\n' "$var"
done

0

sourceD betiğinin değişkenleri boş bir değere ayarlamasının uygun olduğu durumun üstesinden gelmek için özlü (biraz hacky) bir çözüm, betiği kaynaklamadan önce değişkenleri bazı özel değerlere başlatmak ve daha sonra bu değeri kontrol etmektir. , Örneğin

one=#UNSET#
two=#UNSET#
three=#UNSET#

. set_vars_script

if [[ $one$two$three == *#UNSET#* ]] ; then
  echo "One or more essential variables are unset" >&2
  exit 1
fi

1
başka bir güzel çözüm, ama ben "bir veya daha fazla değişken unset" sonra daha spesifik bir hata mesajı vermek istiyorum ...
Jasper

0

Ben uzattığımızı @ mikeserv cevabını .

Bu sürüm, varlığını kontrol etmek, eksik değişkenin adını yazdırmak ve hatalı bir use () çağrısını tetiklemek için değişkenlerin bir listesini alır.

REQD_VALUES=("VARIABLE" "FOO" "BAR" "OTHER_VARIABLE")
( i=0; for var_name in ${REQD_VALUES[@]}; do
    VALUE=${!var_name} ;
    i=$((i+1)) ; : ${VALUE:?$var_name is missing}
done ) || usage

Bir değer eksik olduğunda örnek çıktı:

./myscript.sh: line 42: VALUE: OTHER_VARIABLE is missing

VALUE adlı değişkeni, istediğiniz çıktıya daha iyi uyan alternatif bir adla değiştirebileceğinizi unutmayın.

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.