Tenho um problema com a sh
sintaxe do script. Escrevi um script para meu roteador Asus. O roteiro funciona perfeitamente. Mas eu tenho esta linha:
if [[ "$OldIP" && "$StartIP" != "$OldIP" ]]; then echo OK; fi
Deve ser verdadeiro (e executado echo OK
) somente se $StartIP
e $OldIP
não forem iguais. A linha funciona, mas gostaria de ver isso feito de forma mais eficiente. As variáveis contêm endereços IP válidos.
Em alguns casos, $OldIP
não será atribuído nada (não é inicializado). Mas, se $OldIP
não existir, significa que não são iguais no meu shell!
Não quero que a linha faça: if $OldIP
does not exist -> test if they are different -> run echo OK
.
Eu quero que a linha signifique: a) se $OldIP
não existe -> fim. mais b) se $OldIP
existir -> testar se são diferentes -> executar echo OK
.
Então, eu gostaria de remover "$OLDIP" &&
de alguma forma, se possível. Não é um problema real; curioso para aprender :)
Mais ou menos (mas não funciona):
if [ [ "$OldIP" ] != "$StartIP" ]; then echo OK; fi
ou
if [ $OldIP != "$StartIP" ]; then echo OK; fi
que faz o que eu quero, mas reclama quandoIP antigoestá vazio (mas funciona bem)
enquanto
if [ "$OldIP" != "$StartIP" ]; then echo OK; fi
funciona, mas ignora issoIP antigoestá vazia
Responder1
A rigor, uma variável não existe se nunca lhe foi atribuído um valor, ou se lhe foi atribuído um valor unset
. Uma variável com uma string vazia como valorexiste.
A expansão do parâmetro padrão ${variable+value}
substituirá a string value
quando variable
existir (não estiver desabilitada ou vazia). Isso poderia ser usado para testar a existência assim:
if [ "${OldIP+x}" = "x" ] && [ "$OldIP" != "$StartIP" ]; then
# code
fi
Para testar se OldIP
existe em bash
, use o -v
teste:
if [[ -v OldIP ]] && [[ "$OldIP" != "$StartIP" ]]; then
# code
fi
Isso realizaria a comparação de strings entre $OldIP
e $StartIP
somente se OldIP
tivesse sido definido anteriormente (mesmo que tivesse sido definido como uma string vazia). Observe que o -v
teste leva onomeda variável.
Responder2
Acho que seu script é bastante eficiente como está. Você certamente não está gastando muitos ciclos nisso.
Outra maneira de escrever a lógica:
{ test -n "$OldIP" || test "$StartIP" != "$OldIP"; } && echo OK
Isto diz "se OldIP estiver definido ou se OldIP e StartIP forem diferentes, então ecoe OK.
Lembre-se de que esse [
é outro nome sobre test(1)
o qual você pode ler man 1 test
.
Editar: como Gilles apontou, tome cuidado para evitar a criação de subshells ( ... )
onde eles não são necessários.
{ ... ; }
pode ser usado para agrupar comandos sem executar um novo shell.
Breve referência:http://www.gnu.org/software/bash/manual/html_node/Command-Grouping.html
Responder3
Isso faz o que você pede:
[ "${OldIP:-"$StartIP"}" != "$StartIP" ] && echo "OK"
Como também este (mais complexo):
${OldIP:+false} || { [[ $OldIP != $StartIP ]] && echo "OK"; }
Responder4
Se você estiver usando bash
, poderá usar uma substituição padrão:
[[ "${OldIP:=oldunset}" != "${StartIP?StartUnset" ]] && echo "OK"
A sintaxe ${var:-def}
será avaliada para o valor atual de $var
ou para o padrão especificado (neste caso, def
) se a variável não estiver definida ou for nula. O valor da variável (se houver) permanece inalterado.
A sintaxe ${var?message}
terminará com um código de erro 1 com uma mensagem message
if $var
is unset ou null.
Se você precisar explicitamente test
de testes compatíveis, poderá fazer o seguinte:
[ ! -z "$OldIP" -a "$OldIP" != "$StartIP" ] && echo "OK"