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
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.
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.
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 .
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
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:
${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! ${#missing_vars[@]}
, porque isso é sempre um número inteiro, mesmo que você seja perverso o suficiente para desconsiderar o conselho anterior. %q
ao imprimir; %s
normalmente seria suficiente. >&2
, portanto, não é canalizada para comandos de recebimento de dados 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
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
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
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.
Tags bash shell-script