Compare com eficiência se a variável existe e não é igual

Compare com eficiência se a variável existe e não é igual

Tenho um problema com a shsintaxe 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 $StartIPe $OldIPnã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, $OldIPnão será atribuído nada (não é inicializado). Mas, se $OldIPnão existir, significa que não são iguais no meu shell!

Não quero que a linha faça: if $OldIPdoes not exist -> test if they are different -> run echo OK.

Eu quero que a linha signifique: a) se $OldIPnão existe -> fim. mais b) se $OldIPexistir -> 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 valuequando variableexistir (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 OldIPexiste em bash, use o -vteste:

 if [[ -v OldIP ]] && [[ "$OldIP" != "$StartIP" ]]; then
     # code
 fi

Isso realizaria a comparação de strings entre $OldIPe $StartIPsomente se OldIPtivesse sido definido anteriormente (mesmo que tivesse sido definido como uma string vazia). Observe que o -vteste 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 $varou 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 messageif $varis unset ou null.

Se você precisar explicitamente testde testes compatíveis, poderá fazer o seguinte:

[ ! -z "$OldIP" -a "$OldIP" != "$StartIP" ] && echo "OK"

informação relacionada