bash - O que os parênteses em instruções if fazem? [duplicado]

3

Talvez isso se aplique a mais do que apenas bash, mas estou confuso sobre o papel dos parênteses em instruções if. A maioria dos exemplos parecem ter o seguinte formato

if [ expression ]; then
    #do stuff
fi

Mas isso nem sempre funciona para mim. Por exemplo, eu tenho o seguinte script test.sh :

#!/bin/bash

flag=False
if ! $flag; then
    echo "No brackets: Flag is $flag"
fi
if [ ! $flag ]; then
    echo "With brackets: Flag is $flag"
fi
echo "The end."

Que imprime

$ ./test.sh
No brackets: Flag is False
The end.

Portanto, a instrução usando colchetes é ignorada ou é avaliada como False. Por que isso acontece? O que os parênteses fazem?

Eu também vi colchetes duplos. Como são esses usados?

-

Editar: as perguntas reivindicadas como duplicatas ( e this ) responde apenas a uma pequena parte desta questão. Ainda não estou claro por que a sintaxe com colchetes falharia (parece-me que test ! false deveria avaliar para true ) e por que a sintaxe sem colchetes é bem-sucedida (embora, como menciona @ilkkachu no comentário, parece deveria realmente falhar também?).

    
por dkv 07.06.2017 / 23:40

2 respostas

2

Em qualquer Unix diferente daqueles que possuem sistemas de arquivos que não diferenciam maiúsculas de minúsculas (como macOS), a instrução if

if ! $flag; then
    echo "No brackets: Flag is $flag"
fi

geraria a saída

bash: False: command not found
No brackets: Flag is False

No macOS, o erro não seria gerado, pois o comando False é o mesmo que o comando padrão (externo) false , devido à insensibilidade a maiúsculas e minúsculas do sistema de arquivos.

Em ambos os casos, o teste em ! $flag é verdadeiro (mas por motivos diferentes), então o texto é impresso. Na maioria dos Unices, ! $flag é true, pois ele executa o comando False , falha e a falha é negada. No macOS, ele executa o utilitário externo false , que retorna false, que é negado.

A segunda declaração if ,

if [ ! $flag ]; then
    echo "With brackets: Flag is $flag"
fi

funciona da mesma maneira em qualquer Unix. Ele chama o utilitário [ , que é igual ao utilitário test (mas [ requer um ] correspondente como seu último operando), com os dois argumentos ! e False . Por padrão, test retornará um valor verdadeiro se o argumento de string tiver comprimento diferente de zero, o que ele tem, mas é negado pelo ! so test retorna false e o echo nunca é executado.

Para maior clareza, é melhor usar o teste -n para testar uma string não vazia:

if [ -n "$flag" ]; then ...

ou -z para testar uma string vazia:

if [ -z "$flag" ]; then ...

A citação das expansões de variáveis não é importante nesta parte específica do código, pois $flag se expande para uma única palavra que não é um padrão de globalização de nomes de arquivos. Em geral, no entanto, as expansões variáveis devem ser duplamente citadas para evitar a divisão de palavras e a globalização de nomes de arquivos.

Para uma discussão sobre [ vs. [[ , consulte

Relacionados:

por 15.11.2018 / 19:04
1

A resposta exata é um pouco complexa. Tudo se resume a entender que a palavra false é tanto um comando quanto uma string (dependendo do contexto).

Uma descrição mais longa:

Vamos começar com a string A_Non_Existing_Command .

str=A_Non_Existing_Command

Então, um (em geral: por favor, citar expansões variáveis.)

$ if $str; then echo yes; else echo no; fi
bash: A_Non_Existing_Command: command not found
no

Imprime no , pois o comando executado falha (não existe) e a parte else é executada. Claro, há uma mensagem de erro também (mais tarde).

No entanto, o comando de teste, test ou [ (leia help test dentro do bash) testará se:

the length of the string between brackets is non-zero

E assim:

$ if [ "$str" ]; then echo yes; else echo no; fi
yes

Imprime um sim (como a string tem uma quantidade diferente de zero de caracteres (geralmente bytes)). Não importa que a string seja também o nome de um comando não existente. Nesse caso, o valor da variável é interpretado (avaliado) como uma string.

E, claro, o teste negativo não imprimirá:

$ if [ ! "$str" ]; then echo yes; else echo no; fi
no

Qual é exatamente o equivalente a [ -z "$str" ] .

Agora, alterando o str content para False e executando os mesmos comandos:

 $ str=false
 $ if     "$str"  ; then echo yes; else echo no; fi
 no

 $ if [   "$str" ]; then echo yes; else echo no; fi
 yes

 $ if [ ! "$str" ]; then echo yes; else echo no; fi
 no

Se você obtiver o mesmo com str=False (sem erros), provavelmente é porque você está em um sistema com um sistema de arquivos que não diferencia maiúsculas de minúsculas (onde procurar por False irá encontrar false sem nenhum erro).

    
por 16.11.2018 / 00:36