Como testar se uma variável é definida no Bash antes da versão 4.2 com a opção shell do nounset?

14

Para versões Bash anteriores ao "GNU bash, Versão 4.2" existem alternativas equivalentes para a opção -v do comando test ? Por exemplo:

shopt -os nounset
test -v foobar && echo foo || echo bar
# Output: bar
foobar=
test -v foobar && echo foo || echo bar
# Output: foo
    
por Tim Friske 27.11.2012 / 00:38

3 respostas

32

Portátil para todos os shells do POSIX:

if [ -n "${foobar+1}" ]; then
  echo "foobar is defined"
else
  echo "foobar is not defined"
fi

Faça o ${foobar:+1} se você quiser tratar foobar da mesma maneira, esteja vazio ou não definido. Você também pode usar ${foobar-} para obter uma string vazia quando foobar for indefinido e o valor de foobar (ou colocar qualquer outro valor padrão após o - ).

Em ksh, se foobar for declarado mas não definido, como em typeset -a foobar , então ${foobar+1} se expandirá para a string vazia.

O Zsh não possui variáveis declaradas, mas não configuradas: typeset -a foobar cria uma matriz vazia.

No bash, os arrays se comportam de maneira diferente e surpreendente. ${a+1} apenas se expande para 1 se a for um array não vazio, por exemplo

typeset -a a; echo ${a+1}    # prints nothing
e=(); echo ${e+1}            # prints nothing!
f=(''); echo ${f+1}          # prints 1

O mesmo princípio se aplica a matrizes associativas: variáveis matriciais são tratadas como definidas se tiverem um conjunto não vazio de índices.

Uma maneira diferente e específica para testar se uma variável de qualquer tipo foi definida é verificar se ela está listada em ${!PREFIX*} . Isso informa matrizes vazias conforme definido, ao contrário de ${foobar+1} , mas relata variáveis declaradas, mas não atribuídas ( unset foobar; typeset -a foobar ) como indefinidas.

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

Isso equivale a testar o valor de retorno de typeset -p foobar ou declare -p foobar , exceto que typeset -p foobar falha em variáveis declaradas, mas não atribuídas.

No bash, como em ksh, set -o nounset; typeset -a foobar; echo $foobar dispara um erro na tentativa de expandir a variável indefinida foobar . Ao contrário do ksh, set -o nounset; foobar=(); echo $foobar (ou echo "${foobar[@]}" ) também dispara um erro.

Observe que, em todas as situações descritas aqui, ${foobar+1} se expande para a string vazia se, e somente se, $foobar causar um erro em set -o nounset .

    
por 27.11.2012 / 02:07
5

Para resumir a resposta de Gilles, criei as seguintes regras:

  1. Use [[ -v foobar ]] para variáveis na versão Bash > = 4.2.
  2. Use declare -p foobar &>/dev/null para variáveis de matriz na versão Bash < 4.2
  3. Use (( ${foo[0]+1} )) ou (( ${bar[foo]+1} )) para os índices de matrizes indexadas ( -a ) e codificadas ( -A ) ( declare ), respectivamente. As opções 1 e 2 não funcionam aqui.
por 27.11.2012 / 00:38
3

Eu uso a mesma técnica para todas as variáveis no bash e funciona, por exemplo:

[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"

saídas:

foobar is unset

enquanto

foobar=( "val" "val2" )
[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"

saídas:

foobar is set
    
por 17.04.2013 / 10:38

Tags