Como usar e / ou condicional no shell script

3

Eu tenho uma declaração if em um script.

Parece assim:

if [ "$a" != "0" -a "$b" != "100" ]; then
 #some commands here

Se não me engano, a linha acima funcionará se ambas as condições forem verdadeiras.

Agora, como posso testar que qualquer uma ou ambas as condições são verdadeiras antes de executar some commands ?

    
por cube00 19.06.2015 / 10:59

4 respostas

8

As formas canônicas padrão (POSIX sh e utilities) legíveis seriam:

  • string comparação:

    if [ "$a" != 0 ] || [ "$b" != 100 ]; then...
    
  • decimal inteiro comparação (0100 é 100, se espaços em branco à esquerda são ignorados ou não dependem da implementação embora).

    if [ "$a" -ne 0 ] || [ "$b" -ne 100 ]; then...
    
  • Comparação

    inteiro (0x64, 0144 são 100 (o modo POSIX tem que ser ativado para alguns shells para octais). Dependendo do shell 100.0, 1e2, 50 + 50, ( RANDOM 0.003% do tempo) ... será também):

    if [ "$((a != 0 || b != 100))" -ne 0 ]; then...
    

    No entanto, se o conteúdo das variáveis fizer com que a expansão aritmética falhe com um erro de sintaxe, isso fará com que o shell seja abortado, portanto você pode querer executá-lo em uma subshell para considerar isso.

    if ([ "$((a != 0 || b != 100))" -ne 0 ]); then
    

    Você provavelmente não deve usar esse formulário de qualquer maneira, se o conteúdo das variáveis não estiver sob o seu controle, pois isso seria um vulnerabilidade arbitrária de execução de comandos em muitos shells ( bash , ksh , zsh ) (por exemplo, com valores de $a like x[$(reboot)] ).

Qual você escolherá depende do conteúdo das variáveis e do que você quer que elas sejam. Se você souber que eles contêm números inteiros decimais em sua forma canônica, todos os 3 serão equivalentes.

Em qualquer caso, evite os operadores -a / -o test que depreciado e não confiável no caso geral (não aqui, se você tem controle sobre o conteúdo das variáveis).

    
por 19.06.2015 / 13:59
1

Use avaliação aritmética e parênteses para evitar ambigüidade:

if (( ($a != 0)  || ($b != 100) )); then
# some commands

Ou, se você quiser lidar com strings também, use [[ .

    
por 19.06.2015 / 13:34
1
[ "$((a||b^100))" -eq 1 ] && some commands

A expansão matemática de um shell manipulará as condições booleanas && AND || OR e ! NOT avaliando a expressão como 1 para true ou 0 para false. Ele irá lidar com os operadores bit a bit & AND | OR e ^ XOR também, mas obviamente eles não necessariamente obterão um 0 ou 1, embora uma expressão bit a bit possa servir como um campo para um eval booleano, como faz aqui. Curiosamente, o shell fará até mesmo a coisa do twitt ~ e << left e >> right SHIFTs.

E se a for true OU b^100 for true, a expansão será igual a 1, corresponderá à comparação -eq [ test ] e o shell continuará avaliando o restante de && some commands .

Geralmente, é mais fácil avaliar / comparar inteiros dessa maneira do que tentar encadear ...

...the -a and -o binary primaries and the ( and ) operators [which] have been marked obsolescent. (Many expressions using them are ambiguously defined by the grammar depending on the specific expressions being evaluated.)

(^ citação direta da test spec)

Mesmo quando isso funciona, 4 é o máximo que você pode fazer antes de entrar em território oficialmente não especificado .

No passado, muitas vezes achei útil aplicar uma pequena abstração como:

math(){ return "$((!($1)))"; }

... que pode ser usado como ...

math 'a||b^100' && some commands

Embora isso não tenha sido realmente uma ideia minha: na verdade, peguei o XRAT Rationale :

...[i]t was concluded that the test command ([) was sufficient for the majority of relational arithmetic tests, and that tests involving complicated relational expressions within the shell are rare, yet could still be accommodated by testing the value of "$(())" itself. For example:

    # a complicated relational expression
    while [ "$(( (($x + $y)/($a * $b)) < ($foo*$bar) ))" -ne 0 ] 

...or better yet, the rare script that has many complex relational expressions could define a function like this...

    val() { return "$((!$1))"; }

(eu adicionei o " quotes ^ acima, no entanto. O que há de errado com esses caras?)

    
por 19.06.2015 / 11:29
0

Resposta mais simples do que a que eu vi acima.

if [ "$a" != "0" -o "$b" != "100" ]; then
    
por 22.06.2015 / 10:15