Como usar instruções de caso em scripts Bash

Classificando formas em categorias em um quadro-negro
Patpitchaya / Shutterstock.com

As declarações de caso Bash são poderosas, mas fáceis de escrever. Ao revisitar um script antigo do Linux, você ficará feliz por ter usado uma casedeclaração em vez de uma if-then-elsedeclaração longa .

A declaração do caso

A maioria das linguagens de programação tem sua versão de uma instrução switchou case. Eles direcionam o fluxo de execução do programa de acordo com o valor de uma variável. Normalmente, há uma ramificação de execução definida para cada um dos valores possíveis esperados da variável e uma  ramificação pega-tudo ou  padrão para todos os outros valores.

A funcionalidade lógica é semelhante a uma longa sequência de if-theninstruções com uma elseinstrução capturando tudo o que não foi tratado anteriormente por uma das ifinstruções.

A implementação Bash de case tenta combinar uma  expressão  com uma das cláusulas. Isso é feito examinando cada cláusula, por sua vez, tentando encontrar um padrão correspondente . Padrões em cláusulas são strings, mas – contra-intuitivamente – isso não significa que não podemos usar valores numéricos como a expressão.

O caso genérico

A forma genérica da casedeclaração é esta:

expressão de caso em 

  padrão-1)
    declaração 
    ;;

  padrão-2) 
    declaração
    ;;
    .
    .
    .

  padrão-N) 
    declaração 
    ;;

  *) 
    declaração 
    ;; 
esac

  • Uma casedeclaração deve começar com a casepalavra chave e terminar com a esacpalavra chave.
  • A expressão é avaliada e comparada com os padrões em cada  cláusula  até que uma correspondência seja encontrada.
  • A instrução ou instruções na cláusula correspondente são executadas.
  • Um ponto e vírgula duplo “ ;;” é usado para encerrar uma cláusula.
  • Se houver correspondência de um padrão e as instruções dessa cláusula forem executadas, todos os outros padrões serão ignorados.
  • Não há limite para o número de cláusulas.
  • Um asterisco “ *” indica o padrão padrão. Se uma expressão não corresponder a nenhum dos outros padrões da caseinstrução, a cláusula padrão será executada.
Recomendado:  O que são “IOPS” e importam?

Um Exemplo Simples

Este script nos informa o horário de funcionamento de uma loja imaginária. Ele usa o datecomando com a +"%a"string de formato para obter o nome do dia abreviado. Isso é armazenado na DayNamevariável.

#! / bin / bash

DayName = $ (data + "% a")

echo "Horário de funcionamento de $ DayName"

caso $ DayName em

  Seg)
    echo "09:00 - 17:30"
    ;;

  Ter)
    echo "09:00 - 17:30"
    ;;

  Casar)
    echo "09:00 - 12:30"
    ;;

  Qui)
    echo "09:00 - 17:30"
    ;;

  Sex)
    echo "09:00 - 16:00"
    ;;

  Sentado)
    echo "09:30 - 16:00"
    ;;

  Sol)
    echo "Fechado o dia todo"
    ;;

  *)
    ;;
esac

Copie esse texto em um editor e salve-o como um arquivo chamado “open.sh.”

Precisamos usar o chmodcomando para torná-lo executável. Você precisará fazer isso para todos os scripts que criar ao trabalhar neste artigo.

chmod + x open.sh

Tornando o script open.sh executável

Agora podemos executar nosso script.

./open.sh

Executando o script open.sh

O dia em que a captura de tela foi tirada é uma sexta-feira. Isso significa que a DayName variável contém a string “Fri.” Isso corresponde ao padrão “Fri” da cláusula “Fri)”.

Observe que os padrões nas cláusulas não precisam ser colocados entre aspas duplas, mas não faz mal nenhum se estiverem. No entanto, você deve usar aspas duplas se o padrão contiver espaços.

A cláusula padrão foi deixada em branco. Qualquer coisa que não corresponda a uma das cláusulas anteriores é ignorada.

Esse script funciona e é fácil de ler, mas é prolixo e repetitivo. Podemos encurtar esse tipo de  case declaração com bastante facilidade.

Usando vários padrões em uma cláusula

Um recurso realmente interessante das caseinstruções é que você pode usar vários padrões em cada cláusula. Se a expressão corresponder a qualquer um desses padrões, as instruções dessa cláusula serão executadas.

Aqui está um script que informa quantos dias há em um mês. Só pode haver três respostas: 30 dias, 31 dias ou 28 ou 29 dias para fevereiro. Então, embora sejam 12 meses, só precisamos de três cláusulas.

Neste script, o usuário é solicitado a inserir o nome de um mês. Para tornar o padrão de correspondência insensível a maiúsculas e minúsculas, usamos o shoptcomando com a -s nocasematchopção. Não importa se a entrada contém maiúsculas, minúsculas ou uma mistura dos dois.

#! / bin / bash

shopt -s nocasematch

echo "Digite o nome de um mês"
ler o mês

caso $ mês em

  Fevereiro)
    echo "28/29 dias em $ mês"
    ;;

  Abril | Junho | Setembro | Novembro)
    echo "30 dias em $ mês"
    ;;

  Janeiro | Março | Maio | Julho | Agosto | Outubro | Dezembro)
    echo "31 dias em $ mês"
    ;;

  *)
    echo "Mês desconhecido: $ mês"
    ;;
esac

Fevereiro tem uma cláusula para si mesmo e todos os outros meses compartilham duas cláusulas, dependendo de terem 30 ou 31 dias nelas. As cláusulas de padrões múltiplos usam o símbolo de barra vertical “|” como separador. O caso padrão captura meses mal escritos.

Recomendado:  Como imprimir em PDF no Windows 11

Salvamos isso em um arquivo chamado “month.sh” e o tornamos executável.

chmod + x mês.sh

Executaremos o script várias vezes e mostraremos que não importa se usamos letras maiúsculas ou minúsculas.

./month.sh

Executando o script month.sh com diferentes entradas de caso

Como dissemos ao script para ignorar as diferenças em maiúsculas e minúsculas, qualquer nome de mês digitado corretamente é tratado por uma das três cláusulas principais. Meses mal escritos são capturados pela cláusula padrão.

Usando dígitos em declarações caseiras

Também podemos usar dígitos ou variáveis ​​numéricas como a expressão. Este script pede ao usuário para inserir um número no intervalo 1..3. Para deixar claro que os padrões em cada cláusula são strings, eles foram colocados entre aspas duplas. Apesar disso, o script ainda corresponde à entrada do usuário para a cláusula apropriada.

#! / bin / bash

echo "Digite 1, 2 ou 3:"
ler número

caso $ Number em

  "1")
    echo "Cláusula 1 correspondida"
    ;;

  "2")
    echo "Cláusula 2 correspondida"
    ;;

  "3")
    echo "Cláusula 3 correspondida"
    ;;

  *)
    echo "Cláusula padrão correspondida"
    ;;
esac

Salve em um arquivo chamado “number.sh”, torne-o executável e execute-o:

./number.sh

Executar o script number.sh e testar diferentes entradas do usuário

Usando instruções case em for Loops

Uma caseinstrução tenta corresponder ao padrão de uma única expressão. Se você tiver muitas expressões para processar, pode colocar a caseinstrução dentro de um forloop.

Este script executa o lscomando para obter uma lista de arquivos. No forloop, o arquivo globbing – semelhante, mas diferente das expressões regulares – é aplicado a cada arquivo para extrair a extensão do arquivo. Isso é armazenado na Extensionvariável string.

A caseinstrução usa a Extensionvariável como a expressão que tenta corresponder a uma cláusula.

#! / bin / bash

para arquivo em $ (ls)

Faz
  # extrai a extensão do arquivo
  Extension = $ {File ## *.}

  caso "$ Extension" em

    sh)
      echo "Shell script: $ File"
      ;;

    md)
      echo "Arquivo Markdown: $ File"
      ;;

    png)
      echo "arquivo de imagem PNG: $ File"
      ;;

    *)
      echo "Desconhecido: $ File"
      ;;
  esac
feito

Salve este texto em um arquivo chamado “filetype.sh”, torne-o executável e execute-o usando:

./filetype.sh

Executar o script filetype.sh e identificar arquivos

Nosso script de identificação de tipo de arquivo minimalista funciona.

Recomendado:  Como excluir sua conta do Instagram

Tratamento de códigos de saída com declarações de caso

Um programa bem comportado enviará um código de saída para o shell quando ele for encerrado. O esquema convencional usa um valor de código de saída de zero para indicar uma execução sem problemas e valores de um ou mais para indicar diferentes tipos de erro.

Muitos programas usam apenas zero e um. Agrupar todas as condições de erro em um único código de saída torna a identificação dos problemas mais difícil, mas é uma prática comum.

Criamos um pequeno programa chamado “go-geek” que retornava aleatoriamente códigos de saída zero ou um. Este próximo script chama go-geek. Ele adquire o código de saída usando a $?variável shell e usa-o como a expressão para a caseinstrução.

Um script do mundo real faria o processamento apropriado de acordo com o sucesso ou falha do comando que gerou o código de saída.

#! / bin / bash

go-geek

case $? dentro

  "0")
    echo "A resposta foi: Sucesso"
    echo "Faça o processamento apropriado aqui"
    ;;

  "1")
    echo "A resposta foi: Erro"
    echo "Faça o tratamento de erros apropriado aqui"
    ;;

  *)
    echo "Resposta não reconhecida: $?"
    ;;
esac

Salve isso em um script chamado “return-code.sh” e torne-o executável. Você precisará substituir o nosso go-geekcomando por algum outro comando. Você pode tentar cdentrar em um diretório que não existe para obter um código de saída de um e, em seguida, editar seu script cdpara um diretório acessível para obter um código de saída zero.

A execução do script algumas vezes mostra os diferentes códigos de saída sendo identificados corretamente pela caseinstrução.

./return-code.sh

Executar o script return-code.sh mostrando a manipulação de diferentes códigos de saída

Legibilidade ajuda na manutenção

Voltar aos antigos scripts Bash e descobrir como eles fazem o que fazem, especialmente se foram escritos por outra pessoa, é um desafio. Corrigir a funcionalidade de scripts antigos é ainda mais difícil.

A caseinstrução fornece lógica de ramificação com sintaxe clara e fácil. É uma situação em que todos ganham.