Percursos
/
Bash
Bash
/
Programa
/
Condicionais
Co

Condicionais em Bash

{one: "1 exercício", many: "%{count} exercícios", other: "%{count} exercícios"}

Sobre Condicionais

A veracidade em Bash

O Bash não tem o conceito de valores Boolean. Existem strings e números, e arrays de strings ou de números. Então, como é que os comandos condicionais lidam com verdadeiro e falso?

Estado de saída

Os comandos produzem um estado de saída quando terminam. Um estado de saída é um número inteiro entre 0 e 255, inclusive. O Bash considera que um estado de saída zero representa sucesso. Qualquer outro estado de saída representa falha.

Isto aplica-se a todos os comandos, incluindo comandos internos do Bash, palavras-chave e funções.

O comando "if"

A sintaxe básica do comando if é

if CONDITIONAL_COMMANDS; then TRUE_COMMANDS; else FALSE_COMMANDS; fi

Começa com if; os comandos da condição são separados dos comandos de "sucesso" por then; e termina com fi. A cláusula else é opcional.

CONDITIONAL_COMMANDS pode ser um único comando ou pode ser uma lista de comandos.

Os CONDITIONAL_COMMANDS são executados e

  • se o estado de saída for zero (sucesso), os TRUE_COMMANDS são executados.
  • se o estado de saída não for zero (falha), os FALSE_COMMANDS são executados, se existirem.

É possível indicar ramificações em cascata com elif

if CONDITIONAL_COMMANDS
then TRUE_COMMANDS
elif CONDITIONAL_COMMANDS_2
then TRUE_COMMANDS_2
# more elif branches ...
else FALSE_COMMANDS
fi

É preciso um ponto e vírgula ou uma mudança de linha antes das palavras then, elif, else e fi.

Para reforçar: é o estado de saída dos comandos condicionais que controla o fluxo. Por exemplo, o grep devolve 0 se encontrar uma correspondência e 1 se não encontrar nenhuma. A opção -q suprime a saída, produzindo apenas o estado de saída.

if grep -q "my pattern" my_file; then echo "the pattern is found in the file"; fi

Os comandos "[" e "test"

Não há sintaxe especial em torno dos CONDITIONAL_COMMANDS. Podes estar habituado a ver condicionais assim:

if [ "$password" = "secure" ]; then
    echo "Welcome!"
fi

O [ não é sintaxe especial. É um comando que avalia a expressão condicional e termina com um estado de sucesso ou de falha. Como em todos os comandos, é obrigatório haver espaço em branco entre ele e os seus argumentos.

Na verdade, o [ é um sinónimo do comando test. São exatamente iguais, exceto que o último argumento do [ tem de ser ].

Expressões condicionais

Dentro de [ e ], escreves uma expressão condicional. Algumas expressões condicionais típicas são:

[ -f "$filename" ]             # file operations
[ "$string1" = "$string2" ]    # string comparisons
[ "$num1" -eq "$num2" ]        # arithmetic comparisons

Há muitas mais operações disponíveis; estão listadas na secção Expressões condicionais do Bash do manual.

Note

Nos exemplos acima, repara que todas as variáveis estão entre aspas. Os comandos test e [ são comandos simples, em que os argumentos estão sujeitos à divisão de palavras e à expansão de nomes de ficheiros como qualquer outro comando.

Isto é importante salientar porque as expressões condicionais são avaliadas de forma diferente consoante quantos argumentos forneces:

  • 0 argumentos: o estado de saída não é zero (falha)
  • 1 argumento: o estado de saída é zero (sucesso) se o argumento não estiver vazio, e não é zero se estiver vazio.
  • 2 argumentos: o primeiro argumento tem de ser um operador unário (como [ -z "$name" ]) ou um ! (que nega o estado do teste de 1 argumento)
  • e mais.

Podes obter resultados inesperados se te esqueceres de colocar as aspas:

str=""

# this prints "empty"
if [ -n "$str" ]; then echo "not empty"; else echo "empty"; fi

# leaving the variable unquoted results in incorrect "not empty" output
if [ -n $str ]; then echo "not empty"; else echo "empty"; fi

A palavra-chave "[["

A construção condicional [[...]] não é um comando, é uma palavra-chave. Isto significa que, embora seja tratada como qualquer outro comando, tem regras de análise sintática especiais. O que [[ tem de especial é que as variáveis expandidas dentro dele não estão sujeitas à divisão de palavras nem à expansão de nomes de ficheiros. Isto significa que este comando funciona como esperas, mesmo sem aspas.

if [[ -n $str ]]; then echo "not empty"; else echo "empty"; fi

O [[ suporta todas as expressões condicionais que o test e o [ conseguem tratar. Além disso, o [[ oferece

  • o operador de correspondência de expressões regulares =~,
  • == e != funcionam como operadores de correspondência de padrões glob,
  • && e || como operadores lógicos (regra de análise sintática especial),
  • < e > como operadores "simples" de comparação de strings (regra de análise sintática especial: como são símbolos de redirecionamento, no [ têm de ser escapados).

É amplamente aceite que estas funcionalidades especiais trazem tantas vantagens que se deve usar o [[ em exclusivo. (Por exemplo, o Google Shell Style Guide.)

O comando "case"

O case é outro comando de fluxo de controlo. É semelhante a uma instrução "switch" noutras linguagens.

case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac

A WORD é comparada com cada PATTERN. Quando um corresponde, os COMMANDS são executados.

read -p "Guess the secret word: " word
case "$word" in
    secret) echo "Yes, you guessed it!" ;;
    ??????) echo "That's the right number of letters." ;;
    s*)     echo "You guessed the first letter." ;;
    *)      echo "Not even close! Try again." ;;
esac

Cada cláusula COMMANDS tem de terminar com dois pontos e vírgulas, ;;.

Note
  1. Existem alternativas que permitem a execução de comandos por continuidade e que a correspondência de padrões prossiga. Consulta o manual para mais detalhes.
  2. Lembra-te de que falámos sobre padrões na secção Expansão de nomes de ficheiros do conceito Quoting.
Editar via GitHub A ligação abre numa nova janela ou separador