Teste se várias variáveis estão definidas

17

Eu gostaria de ter certeza que em um certo ponto de um script, após source ing um arquivo de configuração, várias variáveis são definidas e, se não forem, para interromper a execução, informando ao usuário sobre a variável ausente . Eu tentei

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

mas se, por exemplo, $two não estiver definido, o loop nunca será executado por $two . A próxima coisa que tentei foi

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

Mas se dois não estiverem definidos, ainda recebo "two is set to" em vez de "two is not set".

Como posso ter certeza de que todas as variáveis necessárias estão definidas?

Atualização / Solução: sei que existe uma diferença entre "set" e "set, mas empty". Eu agora uso (graças ao link e as respostas para esta pergunta) o seguinte:

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

Assim, se var estiver definido, mas vazio, ainda será considerado inválido.

    
por Jasper 25.03.2014 / 17:00

9 respostas

7

Erro de cotação.

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

Para o futuro: configuração

set -x

antes de executar o código, você teria mostrado o problema. Em vez de adicionar isso ao código, você pode chamar seu script com

bash -vx ./my/script.sh
    
por 25.03.2014 / 17:09
5

A única coisa que você precisa é de citações no seu teste:

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

Funciona para mim.

    
por 25.03.2014 / 17:09
4

Se você quiser que o programa pare:

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

Isso fará o truque. Cada uma das mensagens após o ponto de interrogação é impressa em stderr e o shell pai morre. Bem, OK, então não cada mensagem - apenas um - apenas o primeiro que falha imprime uma mensagem porque o shell morre. Eu gosto de usar esses testes assim:

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

Eu tinha muito mais a dizer sobre isso aqui .

    
por 26.03.2014 / 08:52
2

Você pode adicionar

set -u

para o início do seu script para que ele termine quando tentar usar uma variável não definida.

Um script como

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

resultará em

script.sh: 3: script.sh: foo: parameter not set

Se você estiver usando bash , o erro ficará assim:

script.sh: line 3: foo: unbound variable

    
por 25.03.2014 / 17:49
2

Uma solução que é extremamente amigável testa todos os requisitos e os relata juntos, em vez de falhar no primeiro e exigir que as coisas aconteçam:

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

Eu uso uma variável array para rastrear quais variáveis não foram definidas e uso o resultado para compor uma mensagem para o usuário.

Notas:

  • Eu citei ${required_vars[@]} no loop for principalmente fora do hábito - Eu não aconselho incluir qualquer metacaractere de shell em seus nomes de variáveis!
  • Eu não citei ${#missing_vars[@]} , porque isso é sempre um número inteiro, mesmo que você seja perverso o suficiente para desconsiderar o conselho anterior.
  • usei %q ao imprimir; %s normalmente seria suficiente.
  • A saída de erro sempre vai para o fluxo de erros com >&2 , portanto, não é canalizada para comandos de recebimento de dados
  • O silêncio é dourado - não imprima informações de progresso ou informações de depuração, a menos que especificamente solicitado. Isso torna os erros mais óbvios.
por 25.04.2016 / 19:01
1

bash 4.2 permite testar se uma variável está configurada com o operador -v ; uma variável não definida e uma variável definida para a cadeia vazia são duas condições diferentes:

$ 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
    
por 26.03.2014 / 14:17
1

Eu acho que se você quer dizer not set , então a variável nunca deve ser inicializada. Se você usar [ -n "${!var}" ] , a variável vazia como two="" falhará, enquanto é definida . Você pode tentar isso:

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
    
por 25.03.2014 / 17:23
0

Uma solução concisa (embora um pouco hacky), para lidar com o caso em que é OK para o script source d definir as variáveis para um valor nulo, é inicializar as variáveis para algum valor especial antes de fazer o sourcing do script, e em seguida, verifique esse valor depois, por exemplo,

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
    
por 28.03.2014 / 05:15
0

Eu estendi a resposta @ mikeserv .

Esta versão pega uma lista de variáveis para verificar a presença de, imprimindo o nome da variável perdida e acionando uma chamada para usage () no erro.

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

Exemplo de saída quando um valor está ausente:

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

Note que você pode alterar a variável chamada VALUE para um nome alternativo que se adapte melhor à sua saída desejada.

    
por 25.04.2016 / 16:25