Postagem em destaque

Criando bot do Telegram em Shell script com ShellBot

Estrutura condicional if...then...elif...else...fi

Resumo

Às vezes é preciso determinar diferentes cursos de ação a serem tomados em um Shell Script, dependendo do sucesso ou falha de um comando. O if permite a construção de tais condições, criando assim um desvio de fluxo através de avaliação condicional.

Estrutura do if:
if...then...elif...else...fi

Sintaxe:
if [ TESTE ]; then
    comandos-teste...
elif [ SENAO-TESTE ]; then
    comandos-senao-teste...
else
    comandos-senao...
fi

A lista TESTE é executada, e se o seu status de retorno é zero, a linha comandos-teste é executada, senão a lista SENAO-TESTE é executada, e se o seu status de retorno é zero, a linha comandos-senao-teste é executada, caso contrário a linha comandos-senao é executada. O status de retorno é o status de saída do último comando executando, ou zero se nenhuma condição testada for verdadeira.

O TESTE na maioria das vezes envolve testes de comparação numérica ou de cadeia, mas também pode ser qualquer comando que retorna um status de zero com consegue e algum outro estado se ele vier a falhar.

Expressões utilizadas com if

A tabela abaixo contém as chamadas expressões primárias que compõem o comando TESTE ou uma lista de comandos. Essas expressões são colocadas entre colchetes '[]'. Se a expressão for omitida a condição é avaliada como falso, caso contrário como verdadeiro.


[-a ARQUIVO]Verdadeiro se o ARQUIVO existe.
[-b ARQUIVO] Verdadeiro se o ARQUIVO existe e é um arquivo de bloco especial.
[-c ARQUIVO] Verdadeiro se o ARQUIVO existe e é um arquivo de caráter especial.
[-d ARQUIVO] Verdadeiro se o ARQUIVO existe e é um diretório.
[-e ARQUIVO] Verdadeiro se o ARQUIVO existe.
[-f ARQUIVO] Verdadeiro se o ARQUIVO existe e é um arquivo regular.
[-g ARQUIVO] Verdadeiro se o ARQUIVO existe e seu bit SGID está definido.
[-h ARQUIVO] Verdadeiro se o ARQUIVO existe e é um link simbólico.
[-k ARQUIVO] Verdadeiro se o ARQUIVO existe e seu bit sticky está definido.
[-p ARQUIVO] Verdadeiro se o ARQUIVO existe e é um pipe nomeado (FIFO).
[-r ARQUIVO] Verdadeiro se o ARQUIVO existe e é legível.
[-s ARQUIVO] Verdadeiro se o ARQUIVO existe e tem um tamanho maior que zero.
[-t FD] Verdadeiro se descritor de arquivo FD é aberto e refere-se a um terminal.
[-u ARQUIVO]  Verdadeiro se o ARQUIVO existe e seu SUID (set user ID) bit é definido.
[-w ARQUIVO] Verdadeiro se o ARQUIVO existe e é gravável.
[-x ARQUIVO] Verdadeiro se o ARQUIVO existe e é executável.
[-o ARQUIVO] Verdadeiro se o ARQUIVO existe e é de propriedade do ID de usuário efetivo.
[-G ARQUIVO] Verdadeiro se o ARQUIVO existe e é de propriedade do ID de grupo efetiva.
[-L ARQUIVO] Verdadeiro se o ARQUIVO existe e é um link simbólico.
[-N ARQUIVO] Verdadeiro se o ARQUIVO existe e foi modificado desde a última leitura.
[-S ARQUIVO] Verdadeiro se o ARQUIVO existe e é um soquete.
[ARQUIVO1 nt ARQUIVO2] Verdadeiro se ARQUIVO1 foi alterado mais recentemente do que ARQUIVO2, ou se ARQUIVO1 existe e ARQUIVO2 não.
[ARQUIVO1 -ot ARQUIVO2] Verdadeiro se ARQUIVO1 é mais velho do que ARQUIVO2, ou é ARQUIVO2 existe e ARQUIVO1 não.
[ARQUIVO1 -ef ARQUIVO2] Verdadeiro se ARQUIVO1 e ARQUIVO2 referem-se aos mesmos números de dispositivo e inode.
[-o OptionName ] Verdadeiro se a opção shell "OptionName" está ativada.
[-z TEXTO] Verdadeiro do comprimento se "TEXTO" é zero.
[-n TEXTO] ou [TEXTO] É verdade, se o comprimento de "TEXTO" é diferente de zero.
[TEXTO1 = TEXTO2] Verdadeiro se os textos são iguais. "=" Pode ser usado em vez de "==" para o estrito cumprimento POSIX.
[TEXTO1 != TEXTO2] Verdadeiro se os texto não são iguais.
[TEXTO1 < TEXTO2] Verdadeiro se "texto1" tipo antes "texto2" Lexicograficamente no local atual.
[TEXTO1 > TEXTO2] Verdadeiro se "texto1" tipos depois de "texto2" Lexicograficamente no local atual.

Operadores aritméticos

Operadores aritméticos são usados para executar muitas das operações aritméticas familiares que envolvem o cálculo de valores numéricos representados por literais, variáveis, outras expressões e constantes. Também classificados com operadores aritméticos são os operadores binários, que atuam no nível dos bits individuais dos operandos e deslocam seus padrões de bits para a esquerda ou direita.

[EXP1 -eq EXP2]Verdadeiro se EXP1 é igual a EXP2.
[EXP1 -ne EXP2]Verdadeiro se EXP1 não é igual a EXP2.
[EXP1 -lt EXP2]Verdadeiro se EXP1 é menor que EXP2.
[EXP1 -le EXP2]Verdadeiro se EXP1 é menor ou igual a EXP2.
[EXP1 -gt EXP2]Verdadeiro se EXP1 é maior que EXP2.
[EXP1 -ge EXP2]Verdadeiro se EXP1 é maior ou igual a EXP2.

Operadores lógicos

Os operadores lógicos avaliam múltiplos blocos condicionais como se fosse parte de uma única expressão condicional de um ou mais elementos pré-definidos.

[EXP1 -o EXP2]Verdadeiro se EXP1 ou EXP2 for verdadeiro.
[EXP1 -a EXP2]Verdadeiro se EXP1 e EXP2 forem verdadeiros.
[[EXP1 || EXP2]]Verdadeiro se EXP1 ou EXP2 for verdadeiro. (Somente expansão)
[[EXP1 && EXP2]]Verdadeiro se EXP1 e EXP2 forem verdadeiros. (Somente expansão)
[ ! EXP ]Verdadeiro se EXP for falso. ! Não lógico (NOT)

O uso de colchetes duplos '[[exp]]' determina se a condição avaliada é uma expansão. As expressões são compostas das primárias e expansão de nome não são executadas nas palavras entre o '[[exp]]'; Expansão de til '~', expansão de parâmetros e variáveis, expansão aritmética, substituição de comandos, substituição de processos e remoção de citações são realizadas. Operadores condicionais, como -f deve ser não cotadas para ser reconhecido como primárias.

Quando operadores como '==' e '!=' são usados, a cadeia da direta do operador é considerado um padrão. O valor de retorno é '0' se a cadeia corresponde ou não corresponde o padrão, caso contrário 1. Qualquer parte do padrão pode ser citada para força-lo a ser correspondido como uma string.

Instrução then

A lista comando-teste que segue a declaração then pode ser qualquer comando válido, programa executável, shell script executável ou declaração shell, com exceção do fechamento do if. O then e fi são considerados declarações separadas no shell. Portanto, quando emitidos na linha de comando, eles são separados por um ponto e vírgula. 

Aplicação do if 

1. Operadores condicionais

1.1 Verificando se um arquivo existe.
# Verifica se o arquivo '/etc/group' existe.
if [ -e /etc/group ]; then
    echo 'Arquivo existe'
else
    echo 'Arquivo não existe'
fi

# Saída
Arquivo existe

A operador condicional '-e' verifica se o arquivo especificado existe, executando o primeiro bloco da instrução se a condição for verdadeira, caso contrário executa as instruções em else.

1.2 Verifica se o usuário tem permissão de escrita em um determinado arquivo.
# Testa se o usuário possui permissão de escrita no arquivo.
if [ ! -w /etc/shadow ]; then
    echo 'Você não possui permissão de escrita neste arquivo.'
    exit 1  # Finaliza
fi

# Saída
Você não possui permissão de escrita neste arquivo.

A condição verifica se o usuário atual possui permissões de escrita no arquivo /etc/shadow e o uso do operador lógico ! (Não), inverte a condição. Se for verdadeira ela passa a ser falsa e vice-versa. Neste caso foi tratado apenas a condição falsa, ou seja, as instruções são executadas somente se o usuário não possuir permissões de escrita.

1.3 Testando se uma opção do shell está ativada.
# Verifica se a opção 'noclobber' está ativada.
if [ -o noclobber ]; then
    # Imprime mensagem
    echo 'Seu arquivos estão protegidos'
fi

# Saída
Seus arquivos estão protegidos

Verifica se a opção noclobber está ativa. Quando ativada o sistema não permite gravar dados em um arquivo utilizando os redirecionadores '>>' ou '>'. Essas opções são definidas usando o comando set +|- opção.

2. Operadores aritméticos.

Um teste condicional aplicado em uma lista numérica deve-se utilizar os operadores aritméticos.

2.1 Testa se o valor da variável var é maior que 9. 
# Atribui valor
var=17

# Verifica se valor armazenado em 'var' é maior que 9
if [ $var -gt 9 ]; then
    echo 'Maior que 9'
else
    echo 'Menor ou igual a 9'
fi

# Saída
Maior que 9

A expressão condicional é executada; Se o valor de var for maior que 9, o primeiro bloco de instruções é executado, caso contrário o bloco else é executado.

2.2 Verificando se o valor de var é igual a 12.
# Atribui valor
var=10

# Verifica se valor armazenado em 'var' é igual a 12
if [ $var -eq 12 ]; then
    echo 'Igual a 12'
else
    echo 'Diferente de 12'
fi

# Saída
Diferente de 12

A expressão é testada; Como o valor armazenado na variável é diferente de 12 e não havendo mais testes condicionais, o bloco else é executado.

2.3 Executando vários testes condicionais.
# Atribui valor
num=3

# Testando o valor de num.
if [ $num -eq 2 ]; then
    echo 'Igual a 2'
elif [ $num -eq 3 ]; then
    echo 'Igual a 3'
else
    echo 'Diferente de 2 e 3'
fi

# Saída
Igual a 3

O primeiro teste condicional é executado, então a expressão é marcada como falso, pois o valor de num é diferente de 2; Então o segundo teste condicional é executado e a expressão é avaliada como verdadeira, pois o valor de num é igual a 2. O bloco else não é executado.

3. Operadores lógicos

3.1 Verificando se um número está dentro de um intervalo.
# Variável
num=14

# Operador lógico
# Verifica se 'num' é maior ou igual a 10; Ou se 'num' é menor ou igual a 20.
if [ $num -ge 10 -o $num -lt 20 ]; then
    echo 'O número é maior que 10 e menor que 20'
else
    # Senão
    echo 'Fora do intervalo'
fi

# Saída
O número é maior que 10 e menor que 20

A expressão contendo o operador lógico '-o' retorna verdadeiro se qualquer uma das condições for avaliada como verdadeira. Ou seja, se num for maior ou igual a 10 ou se num for menor ou igual a 20; Caso contrário a instrução else é executada.

3.2 Verificando se ambas condições são verdadeiras.
# Variáveis
num1=5
num2=10

# Operador condicional
# Verifica se 'num1' é igual a 5 e se 'num2' é igual a 10
if [ $num1 -eq 5 -a $num2 -eq 10 ]; then
    echo 'num1 é igual a 5 e num2 é igual a 10'
fi

# Saída
num1 é igual a 5 e num2 é igual a 10

A expressão com o operador logico '-a' só retorna verdadeiro se ambas as condições forem verdadeiras.

Os operadores lógicos '-a' e '-o' não podem ser usados em if's expansivos. Ou seja, quando utilizamos colchetes duplos '[[...]]'. Nesses casos utiliza-se os operadores || (OU) e && (E).

4. Comparando strings

4.1 Verificando se  as strings são iguais.
# Variável
string='Shell'

# Compara o valor armazenado em 'string' com 'shell'
if [ "$string" = 'Shell' ]; then
    echo 'Iguais'
else
    # Senão
    echo 'Diferentes'
fi

# Saída
Iguais

O valor de string é comparado com a expressão Shell, se a condição for verdadeira, executa as instruções do primeiro bloco, caso contrário executada as instruções em else. O método de comparação é bit a bit, onde diferenças entre caracteres maiúsculos e minúsculos são consideradas.

4.2 Testando diferença entre strings.
# Variável
string='Shell2'

# Compara o valor armazenado em 'string' com 'shell'
if [ "$string" != 'Shell' ]; then
    echo 'Diferentes'
else
    # Senão
    echo 'Iguais'
fi

# Saída 
Diferentes 

4.3 Verificando se a variável está vazia.
# Testa se a variável de ambiente 'PATH' está vazia.
if [ -z "$PATH" ]; then
    echo 'Vazia'
else
    # Senão
    # Imprime o conteúdo do variável.
    echo $PATH
fi

# Sda
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

Também podemos utilizar uma condição negada para substituir o operador '-z' na expressão condicional. Exemplo. Substituir [ -z "$PATH" ] por [ ! "$PATH" ]; Obteria o mesmo resultado.


5. Expressões compostas

Para tratar expressões compostas é necessário a utilização de colchetes duplos na declaração do if. Exemplo. 'if [[expressao]]; then ...'. No inicio uma boa parte dos usuários que estão começando a programar em shell, não possuem a boa prática da colocação das variáveis entre as aspas duplas "$var". Omitir as aspas faz com que o conteúdo da variável seja interpretado como diversos elementos, caso haja uma expressão composta armazenada.

Exemplo:

# Expressão simples
nome='Fernanda'

# Usando a variável sem aspas
if [ $nome = 'Fernanda' ]; then
    echo 'Igual'
else
    echo 'Diferente'
fi

# Saída
Igual

Apesar de não declarar a variável entre aspas duplas, não ocorreu nenhum erro; Porque a expressão armazenada na variável era simples, constituída de um único elemento

Utilizando o mesmo exemplo, porém armazenando um nome composto.

# Expressão composta
nome='Fernanda Souza'

# Usando a variável sem aspas
if [ $nome = 'Fernanda Souza' ]; then
    echo 'Igual'
else
    echo 'Diferente'
fi

# Saída
bash: [: número excessivo de argumentos
Diferente

É retornado uma mensagem de erro, informando o uso excessivo de argumentos. O comando if trata o código de retorno executando as instruções em else. (Definindo a condição como falsa pelo erro gerado)

Com colchetes duplos.
# Expressão composta
nome='Fernanda Souza'

# Usando a variável sem aspas, porém com colchetes duplos.
if [[ $nome = 'Fernanda Souza' ]]; then
    echo 'Igual'
else
    echo 'Diferente'
fi

# Saída
Igual

O uso dos colchetes duplos [[..]] faz com que o if interprete a expressão composta com uma única string protegida.

6. Expressões regulares.

O if utiliza o operador binário adicional '=~'. Ele possui a mesma precedência que '==' e '!='. A cadeia de caracteres para a direita do operador é considerado uma expressão regular estendida e combinados com conformidade (como em uma expressão regular). O valor de retorno é 0 se a string corresponder ao padrão, caso contrário 1. Se a expressão regular é sintaticamente incorreta, o valor de retorno da expressão condicional é 2. Se a opção nocasematch do shell está habilitada, a expressão é avaliada sem conta com caracteres alfabéticos. Qualquer parte do padrão pode ser citada para forçá-lo a corresponder com uma string. Substrings pareados com subexpressões ente parênteses dentro da expressão regular são salvos na matriz BASH_REMATCH. O elemento de BASH_REMATCH com o índice 0 é a parte da cadeia combinada na expressão regular. O elemento de índice 'N' é a parte da cadeia correspondente ao nº da expressão entre parênteses.

As expressões podem ser combinadas usando os seguintes operadores, listados em ordem decrescente de precedência:

(Expressão)

Retorna o valor da expressão. Isso pode ser usado para substituir a precedência normal de operadores.

6.1 Verifica se o número é par.
# Valor
num=3212

# Expressão regular que avalia se o valor armazenado em 'num' é par
if [[ $num =~ ^[0-9]*[02468]$ ]]; then
    echo 'O número é par'
else
    # Senão.
    echo 'O número é impar'
fi

# Saída
O número é par

A expressão regular dentro de uma expressão condicional, deve ser declarada sem o uso de aspas simples (') ou duplas ("), pois tais caracteres são interpretados de uma forma literal.

6.2  Verificando se o valor armazenado na variável é do tipo numérico.
# valor
num=12

# Verifica se o valor é um inteiro negativo ou positivo.
if [[ $num = ?(+|-)+([0-9]) ]]; then
    echo 'Número'
else
    echo 'String'
fi

# Saída
Número

6.3 Validando parte da expressão.
# variável
nome='juliano'

# Casa qualquer nome iniciado com 'jul'.
if [[ $nome = jul* ]]; then
    echo 'Nome válido'
else
    echo 'Invalido'
fi

# Saída
Nome válido

Toda expressão que iniciar com 'jul' é validada. Exemplo: juliano, julia, julio, juliana, julho e etc.

7. Testando código de retorno

O código de retorno do último comando executado fica armazenado na variável $?. Informando se o comando foi executado corretamente (Retorna: 0) ou ocorreu alguma falha (Diferente de: 0). Leia: Funções.

7.1 Verificando se um arquivo existe.
# Acessa o arquivo se ele existir, redirecionando a saída padrão para o buraco negro.
ls arquivo &>/dev/null

# Verificando o código de retorno
if [ $? -eq 0 ]; then
    echo 'Arquivo existe.'
else
    echo 'Arquivo não encontrado.'
fi

# Saída
Arquivo não encontrado.

O comando ls tenta acesso ao arquivo. A razão de redirecionar a saída do comando para /dev/null, é porque somente o código de retorno que importa. O if testa o valor, se $? for igual a 0 (zero), indica que o arquivo existe, caso contrário o mesmo não existe.

Atenção quando for avaliar a variável $?, certifique-se que a estrutura if é subsequente ao comando a ser testado.

Usando o exemplo acima, inserindo apenas o comando 'echo' entre o comando a ser testado e o teste condicional.
# Acessa o arquivo se ele existir, redirecionando a saída padrão para o buraco negro.
ls arquivo &>/dev/null

# ERRADO
echo 

# Verifica o código de retorno do comando 'echo'
if [ $? -eq 0 ]; then
    echo 'Arquivo existe.'
else
    echo 'Arquivo não encontrado.'
fi

# Saída

Arquivo existe.

Note que mesmo o arquivo não existindo, o teste condicional foi avaliado como verdadeiro, porque o código de retorno armazenado em $? é do comando echo (último comando executado).

Podemos avaliar o retorno do comando diretamente, declarando-o na estrutura comando-teste do if, omitindo os colchetes '[...]'.

Exemplo: if COMANDO...; then...fi 

7.2 Verificando um arquivo existente.
# Executa o comando e testa o código de retorno.
if ls /etc/group &>/dev/null; then
    echo 'Arquivo existe.'
else
    # Senão
    echo 'Arquivo não encontrado.'
fi

# Saída
Arquivo existe.

7.3 Verificando se uma string está presente em uma expressão.
# Expressão
FRASE='Estou estudando e aprendendo muito sobre Linux. Só liberdade.'

# Busca a palavra 'Linux' na expressão armazenada em 'FRASE'
# executando o grep em modo silencioso.
if echo $FRASE | grep -iwq 'Linux'; then
    echo 'Você está falando sobre Linux.'
fi

# Saída
Você está falando sobre Linux.

O echo imprime o conteúdo da variável, redirecionando para o grep que busca o padrão 'Linux' em modo silencioso (-q). Retorna 0 (zero) se o padrão for encontrado, caso contrário retorna 1.

Aplicação prática

Criei um script que gera um arquivo modelo, contendo um cabeçalho padrão de informações sobre o projeto.

Script: xmodelo_script.sh

#!/bin/bash

#---------------------------------------------------------------------------------
# Data:        28 de Dezembro de 2016
# Script:      xmodelo_script.sh
# Descrição:   Gera um template contendo um cabeçalho com informações do projeto.
# Criado por:  Juliano Santos [SHAMAN]
# Página:      http://www.shellscriptx.blogspot.com.br
# Panpage:     https://www.facebook.com/shellscriptx
#---------------------------------------------------------------------------------

# Nome do script
SCRIPT=$(basename "$0")

# Sem erros
ERR=0

echo 'Criar modelo'
echo

# Lê os dados
read -p 'Script: ' NSCRIPT
read -p 'Descrição: ' DESCRICAO
read -p 'Site: ' SITE

# Remove a extensão do arquivo se ela existir.
# adiciona a extensão 'sh' e armazena o caminho/nome do script.
ARQUIVO="${PWD}/${NSCRIPT%%.*}.sh"

#-----------------ESTRUTURA CONDICIONAL--------------------

# Verifica se há campos vazios.
if [ -z "$SCRIPT" -o -z "$DESCRICAO" -o -z "$SITE"  ]; then
 echo "$SCRIPT: todos os campos são obrigatórios."
 # Erro
 ERR=1
# Requerimento mínimo de caracteres para descrever a função do script.
elif [ ${#DESCRICAO} -lt 20 ]; then
 echo "$SCRIPT: a descrição precisa ter no mínimo 20 caracteres."
 # Erro
 ERR=1
# Testa se o arquivo de script já existe. 
elif [ -e "$ARQUIVO" ]; then
 echo "$SCRIPT: '$ARQUIVO' arquivo já existe."
 # Erro
 ERR=1
# Cria lista negada com '!'.
# Expressão regular que valida se o endereço informado é uma url válida.
# O endereço precisa iniciar com 'http://', sendo que a expressão 'www' é opcional e 
# termine com qualquer um dos dominios: '.com', '.com.br', '.net' ou '.org'.
elif [[ ! $SITE =~ ^http://(www\.)?[a-zA-Z0-9_-]+\.(com\.br|com|net|org)$ ]]; then
 echo "$SCRIPT: '$SITE' endereço inválido."
 # Erro
 ERR=1
fi

# Verifica o valor de 'ERR'
# 0 - OK
# 1 - Erro (Finaliza o script)
if [ $ERR -eq 1 ]; then
 echo 'Finalizando...'
 exit 1
fi

#-----------------------------------------------------------
# Cria o arquivo e monta o cabeçalho com os dados informados.
cat > "$ARQUIVO" << EOF
#!/bin/bash

#-----------------------------------------------------------------
# Data        $(date +%c)
# Script:     $(basename $ARQUIVO)
# Descrição:  $DESCRICAO
# Criado por: $USER
# Página:     $SITE
#-----------------------------------------------------------------

# --> SEU CÓDIGO COMEÇA AQUI <--
EOF

# Teste o código de retorno para constatar se o arquivo foi criado ou não
if [ $? -eq 0 ]; then
 echo "$SCRIPT: script criado com sucesso."
 # Dá permissão de execução para o script criado.
 chmod +x "$ARQUIVO"  
else
 echo "$SCRIPT: não foi possível criar o arquivo."
fi

exit $?
#FIM


Espero que você tenha curtido a estrutura condicional e o quanto ela é fundamental para determinar o fluxo de execução em um script ou programa.

Se você ainda não teve a oportunidade de participar da nossa comunidade; Não perca tempo e junte-se a nós no Telegram. Clique aqui

Um grande abraço e até a próxima.

Comentários

Contato

Nome

E-mail *

Mensagem *