Como validar a sintaxe de um script Bash do Linux antes de executá-lo


0
Um terminal Linux na tela do laptop sobre um pano de fundo vermelho.
fatmawati achmad zaenuri/Shutterstock

Bugs e erros de digitação em scripts Linux Bash podem fazer coisas terríveis quando o script é executado. Aqui estão algumas maneiras de verificar a sintaxe de seus scripts antes mesmo de executá-los.

Esses insetos chatos

Escrever código é difícil. Ou, para ser mais preciso, escrever código não trivial livre de bugs é difícil. E quanto mais linhas de código houver em um programa ou script, mais provável será que haja bugs nele.

A linguagem em que você programa tem uma relação direta com isso. Programar em assembly é muito mais difícil do que programar em C, e programar em C é mais desafiador do que programar em Python. Quanto mais baixo nível for a linguagem em que você estiver programando, mais trabalho terá que fazer sozinho. Python pode desfrutar de rotinas de coleta de lixo embutidas, mas C e assembly certamente não.

Escrever scripts de shell do Linux apresenta seus próprios desafios. Com uma linguagem compilada como C, um programa chamado compilador lê seu código-fonte – as instruções legíveis por humanos que você digita em um arquivo de texto – e o transforma em um arquivo executável binário. O arquivo binário contém as instruções do código de máquina que o computador pode entender e agir.

O compilador só irá gerar um arquivo binário se o código fonte que está lendo e analisando obedecer a sintaxe e outras regras da linguagem. Se você soletrar um palavra reservada—uma das palavras de comando da linguagem—ou um nome de variável incorreto, o compilador lançará um erro.

Por exemplo, algumas linguagens insistem que você declare uma variável antes de usá-la, outras não são tão exigentes. Se a linguagem em que você está trabalhando exigir que você declare variáveis, mas você se esqueça de fazer isso, o compilador lançará uma mensagem de erro diferente. Por mais irritantes que sejam esses erros em tempo de compilação, eles detectam muitos problemas e forçam você a resolvê-los. Mas mesmo quando você tem um programa que não tem erros sintáticos isso não significa que não há bugs nele. Longe disso.

Erros devidos a falhas lógicas geralmente são muito mais difíceis de detectar. Se você disser ao seu programa para somar dois e três, mas você realmente queria que ele somasse dois e dois, você não obterá a resposta que esperava. Mas o programa está fazendo o que foi escrito para fazer. Não há nada de errado com a composição ou sintaxe do programa. O problema é você. Você escreveu um programa bem formado que não faz o que você queria.

Testar é difícil

Testar completamente um programa, mesmo um simples, é demorado. Executá-lo algumas vezes não é suficiente; você realmente precisa testar todos os caminhos de execução em seu código, para que todas as partes do código sejam verificadas. Se o programa solicitar entrada, você precisará fornecer um intervalo suficiente de valores de entrada para testar todas as condições, incluindo entradas inaceitáveis.

Para linguagens de alto nível, testes de unidade e testes automatizados ajudam a tornar o teste completo um exercício gerenciável. Portanto, a questão é: existem ferramentas que podemos usar para nos ajudar a escrever scripts de shell Bash livres de bugs?

A resposta é sim, incluindo o próprio shell Bash.

Usando o Bash para verificar a sintaxe do script

A critica -n (noexec) diz ao Bash para ler um script e verificar se há erros sintáticos, sem executar o script. Dependendo do que seu script pretende fazer, isso pode ser muito mais seguro do que executá-lo e procurar problemas.

Aqui está o script que vamos verificar. Não é complicado, é principalmente um conjunto de if afirmações. Ele solicita e aceita um número que representa um mês. O script decide a qual estação o mês pertence. Obviamente, isso não funcionará se o usuário não fornecer nenhuma entrada ou se fornecer uma entrada inválida como uma letra em vez de um dígito.

#! /bin/bash

read -p "Enter a month (1 to 12): " month

# did they enter anything?
if [ -z "$month" ]
then
  echo "You must enter a number representing a month."
  exit 1
fi

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); then
  echo "The month must be a number between 1 and 12."
  exit 0
fi

# is it a Spring month?
if (( "$month" >= 3 && "$month" < 6)); then
  echo "That's a Spring month."
  exit 0
fi

# is it a Summer month?
if (( "$month" >= 6 && "$month" < 9)); then
  echo "That's a Summer month."
  exit 0
fi

# is it an Autumn month?
if (( "$month" >= 9 && "$month" < 12)); then
  echo "That's an Autumn month."
  exit 0
fi

# it must be a Winter month
echo "That's a Winter month."
exit 0

Esta seção verifica se o usuário digitou alguma coisa. Ele testa se o $month variável não está definida.

if [ -z "$month" ]
then
  echo "You must enter a number representing a month."
  exit 1
fi

Esta seção verifica se eles inseriram um número entre 1 e 12. Ela também intercepta entradas inválidas que não são um dígito, porque letras e símbolos de pontuação não se traduzem em valores numéricos.

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); then
  echo "The month must be a number between 1 and 12."
  exit 0
fi

Todas as outras cláusulas If verificam se o valor na $month variável está entre dois valores. Se for, o mês pertence a essa estação. Por exemplo, se o mês inserido pelo usuário for 6, 7 ou 8, é um mês de verão.

# is it a Summer month?
if (( "$month" >= 6 && "$month" < 9)); then
  echo "That's a Summer month."
  exit 0
fi

Se você quiser trabalhar com nossos exemplos, copie e cole o texto do script em um editor e salve-o como “seasons.sh”. Em seguida, torne o script executável usando o chmod comando:

chmod +x seasons.sh

Configurando a permissão executável em um script

Podemos testar o script por

  • Fornecendo nenhuma entrada em tudo.
  • Fornecendo uma entrada não numérica.
  • Fornecendo um valor numérico que está fora do intervalo de 1 a 12.
  • Fornecendo valores numéricos dentro do intervalo de 1 a 12.

Em todos os casos, iniciamos o script com o mesmo comando. A única diferença é a entrada que o usuário fornece quando promovido pelo script.

./seasons.sh

Testando um script com uma variedade de entradas válidas e inválidas

Isso parece funcionar como esperado. Vamos fazer com que o Bash verifique a sintaxe do nosso script. Fazemos isso invocando o -n (noexec) e passando o nome do nosso script.

bash -n ./seasons.sh

Usando Bash para testar a sintaxe de um script

Este é um caso de “nenhuma notícia é uma boa notícia”. Retornar silenciosamente ao prompt de comando é a maneira de Bash dizer que tudo parece estar bem. Vamos sabotar nosso script e introduzir um erro.

Nós vamos remover o then desde o primeiro if cláusula.

# is it a valid month?
if (( "$month" < 1 || "$month" > 12)); # "then" has been removed
  echo "The month must be a number between 1 and 12."
  exit 0
fi

Agora vamos executar o script, primeiro sem e depois com entrada do usuário.

./seasons.sh

Testando um script com entradas inválidas e válidas

Na primeira vez que o script é executado, o usuário não insere um valor e, portanto, o script termina. A seção que sabotamos nunca é alcançada. O script termina sem uma mensagem de erro do Bash.

Na segunda vez que o script é executado, o usuário fornece um valor de entrada e a primeira cláusula if é executada para verificar a integridade da entrada do usuário. Isso aciona a mensagem de erro do Bash.

Observe que o Bash verifica a sintaxe dessa cláusula – e todas as outras linhas de código – porque não se importa com o lógica do roteiro. O usuário não é solicitado a inserir um número quando o Bash verifica o script, porque o script não está em execução.

Os diferentes caminhos de execução possíveis do script não afetam como o Bash verifica a sintaxe. O Bash funciona de forma simples e metódica do início ao fim do script, verificando a sintaxe de cada linha.

O utilitário ShellCheck

Um linter – nomeado para uma ferramenta de verificação de código fonte C do auge do Unix – é uma ferramenta de análise de código usada para detectar erros de programação, erros de estilo e uso suspeito ou questionável da linguagem. Linters estão disponíveis para muitas linguagens de programação e são conhecidos por serem pedantes. Nem tudo que um linter encontra é um bug por simas qualquer coisa que eles tragam ao seu conhecimento provavelmente merece atenção.

ShellCheck é uma ferramenta de análise de código para scripts de shell. Ele se comporta como um linter para Bash.

Vamos colocar nossa falta then palavra reservada de volta ao nosso script e tente outra coisa. Removeremos o colchete de abertura “[”doprimeiro[”fromtheveryfirstif cláusula.

# did they enter anything?
if -z "$month" ] # opening bracket "[" removed
then
  echo "You must enter a number representing a month."
  exit 1
fi

se usarmos o Bash para verificar o script, ele não encontrará um problema.

bash -n seasons.sh
./seasons.sh

Uma mensagem de erro de um script que passou na verificação de sintaxe sem problemas detectados

Mas quando tentamos corre o script, vemos uma mensagem de erro. E, apesar da mensagem de erro, o script continua a ser executado. É por isso que alguns bugs são tão perigosos. Se as ações executadas posteriormente no script dependerem de uma entrada válida do usuário, o comportamento do script será imprevisível. Isso poderia colocar os dados em risco.

A razão pela qual o Bash -n (noexec) opção não encontra o erro no script é o colchete de abertura “[”éumprogramaexternochamado[”isanexternalprogramcalled[. Não faz parte do Bash. É uma forma abreviada de usar o test comando.

O Bash não verifica o uso de programas externos ao validar um script.

Instalando o ShellCheck

ShellCheck requer instalação. Para instalá-lo no Ubuntu, digite:

sudo apt install shellcheck

Instalando shellcheck no Ubuntu

Para instalar o ShellCheck no Fedora, use este comando. Observe que o nome do pacote está em maiúsculas e minúsculas, mas quando você emite o comando na janela do terminal, tudo está em minúsculas.

sudo dnf install ShellCheck

Instalando shellcheck no Fedora

No Manjaro e distribuições semelhantes baseadas em Arch, usamos pacman:

sudo pacman -S shellcheck

Instalando shellcheck no Manjaro

Usando ShellCheck

Vamos tentar executar ShellCheck em nosso script.

shellcheck seasons.sh

Verificando um script com ShellCheck

ShellCheck encontra o problema e o relata para nós, e fornece um conjunto de links para mais informações. Se você clicar com o botão direito do mouse em um link e escolher “Abrir link” no menu de contexto que aparece, o link será aberto em seu navegador.

ShellCheck relatando erros e avisos

O ShellCheck também encontra outro problema, que não é tão sério. É relatado em texto verde. Isso indica que é um aviso, não um erro completo.

Vamos corrigir nosso erro e substituir o “[”ausenteUmaestratégiadecorreçãodebugécorrigirosproblemasdeprioridademaisaltaprimeiroetrabalharparaosproblemasdeprioridademaisbaixacomoavisosdepois[”Onebug-fixstrategyistocorrectthehighestpriorityissuesfirstandworkdowntothelowerpriorityissueslikewarningslater

Substituímos o “[”ausenteeexecutamosoShellCheckmaisumavez[”andranShellCheckoncemore

shellcheck seasons.sh

Verificando um script uma segunda vez com ShellCheck

A única saída de ShellCheck refere-se ao nosso aviso anterior, então isso é bom. Não temos problemas de alta prioridade que precisam ser corrigidos.

O aviso nos diz que usar o read comando sem o -r (ler como está) fará com que quaisquer barras invertidas na entrada sejam tratadas como caracteres de escape. Este é um bom exemplo do tipo de saída pedante que um linter pode gerar. No nosso caso, o usuário não deveria estar digitando uma barra invertida de qualquer maneira – precisamos que ele digite um número.

Avisos como este requerem um julgamento por parte do programador. Fazer o esforço para corrigi-lo, ou deixá-lo como está? É uma correção simples de dois segundos. E isso impedirá que o aviso atrapalhe a saída do ShellCheck, então podemos seguir seu conselho. Adicionaremos um “r” para optar pelos sinalizadores no read comando e salve o script.

read -pr "Enter a month (1 to 12): " month

A execução do ShellCheck mais uma vez nos dá um atestado de saúde.

Nenhum erro ou aviso relatado pelo ShellCheck

ShellCheck é seu amigo

ShellCheck pode detectar, relatar e aconselhar sobre uma ampla gama de problemas. Confira a galeria de código ruim, que mostra quantos tipos de problemas ele pode detectar.

É grátis, rápido e tira muito do trabalho de escrever scripts de shell. O que há para não gostar?


Like it? Share with your friends!

0

What's Your Reaction?

hate hate
0
hate
confused confused
0
confused
fail fail
0
fail
fun fun
0
fun
geeky geeky
0
geeky
love love
0
love
lol lol
0
lol
omg omg
0
omg
win win
0
win

0 Comments

Your email address will not be published. Required fields are marked *