Tabela de conteúdos

Programação Shell Script: boas práticas

Antes veja Desenvolvimento de sistemas: boas práticas

Esse é um guia pessoal de referência. Na maioria dos casos a dica se baseia no Shell Bash, mas muitas são genéricas. Anoto aqui dicas que considero úteis, de modo que possa acessá-las de qualquer lugar, aproveitando para compartilhar com quem possa ter interesse.

Ao longo de alguns anos programando a gente vai adquirindo alguns hábitos e aprendendo algumas boas dicas quando trocamos experiências com colegas ou aprendemos mais novidades estudando.

Naturalmente algumas dicas aqui provavelmente servirão pra outras linguagens de programação. A medida que eu perceber isso vou tentar marcá-las como “DICA GERAL

Referências Externas

Gerais

Frameworks

IDE

IDE é a sigla de Integrated Development Environment, que simplesmente se refere ao programa que se usa para escrever o código. Eu costumo escrever usando o Vim (Vi IMproved). Sendo ele um editor genérico, é interessante configurá-lo pra facilitar a programação em shell.

Documentação

Uma etapa bem sedimentada nos conceitos de engenharia de software é a documentação. Já vi muita documentação de sistemas e muito trabalho sendo contratado que exigia a criação de uma. Há uma documentação, porém, pra qual muitas vezes não é dada a devida atenção, seja em contratos comerciais, seja na verificação do produto final, mesmo que gerado internamente numa empresa ou por uma pequena equipe: comentários e código bem escrito.

Comentários - DICA GERAL

Código bem escrito

Cabeçalho - DICA GERAL

Use um cabeçalho padrão nos seus códigos. Um bom cabeçalho pode conter:

Interrompendo o programa em caso de erros

Alguns erros podem passar limpos pela execução de um shell e isso pode causar problemas difíceis de solucionar depois que o código cresce muito. Uma dica é colocar sempre no início do script a definição:

set -euo pipefail

(Fonte:Artigo externo)

Estrutura do programa

Testes automatizados

Existem linguagens que tem ferramentas pra facilitar isso, existe alias o BATS (veja também esse guia) pro shell Bash, mas trabalhando com o conceito é possível fazer pra qualquer linguagem. Como Bash trabalha com funções, o melhor é refatorar o código de modo que funções recebam e retornem valores ou que executem coisas verificáveis, viabilizando testes externos que não necessariamente precisem executar as tarefas reais ou no ambiente real.

Um script muitas vezes é pequeno e, nesses casos, a criação de testes talvez não se justifique. Se começar a crescer, se for complexo, se for ser alterado de tempos em tempos, então pode se considerar essa criação dos testes, que garantirá o funcionamento esperado de cada parte do código, evitando que uma eventual alteração faça com que se crie um bug. Essa é a moral da coisa.

Refatoração para viabilizar
* Dividir o código colocando as partes que se quer testar em funções que possam ser testadas separadamente. Sem divisão fica complicado testar todo o código e fica complicado se referir a partes de um código inteiro.

script testador X modo teste
* Para criar um script externo que teste o principal, o ideal é que o programa principal só seja executado se não for um teste. Ao colocarmos o código separado em funções podemos testar se o principal deve rodar ou não. Para carregar as funções do script principal no script testador usamos a sintaxe:

source principal.sh

e as funções estarão disponíveis dentro do testador, não sendo executada nenhuma. Ao executar o principal diretamente, o programa principal dispara os processos. Como fazer essa diferenciação? Através da variável “$0”. Ao chamar um script diretamente, o $0 assume o nome do script. Quando carregamos com o “source” ficamos com “$0 = -bash”. A parte principal do script deve, portanto, ter sua execução condicionada:

## PROGRAMA PRINCIPAL
  if [ "$0" != "-bash" ]; then
    echo "programa principal"
  fi

Os resultados da execução de cada uma das formas é o previsto:

$ source principal.sh
  $ . principal.sh
  $ ./principal.sh
  programa principal
  $ bash principal.sh
  programa principal

Notas:

De resto, portanto, é colocar em funções o que é necessário testar no código e chamar elas dentro da parte principal do programa (que não será testada) e dentro do script testador, que promoverá, idealmente, uma série de testes, verificando o comportamento de cada função para N situações diversas, de modo a garantir a estabilidade do código.

Ferramentas auxiliares

Dicas da linguagem

Arquivos temporários ou em memória

No Bash podemos usar a sintaxe:

comando1 <( comando0 )

onde o trecho “<( comando0 )” se comporta como um arquivo para o “comando1”. Dessa forma, se precisamos lidar com um conteúdo gerado pelo comando0 mas o comando1 só trabalha com arquivo, podemos trabalhar apenas em memória, sem a necessidade de criar um arquivo temporário em disco, o que consome mais código, mais recursos e mais tempo de programação e execução.

Referência: Bash redirections cheat sheet

Exemplo: definindo múltiplas variáveis

read filesystem total used free perc name < <(df . | tail -1)

Lendo linha a linha e atribuindo colunas a variáveis

echo "Sistema"
echo "  disponivel"
df | grep -v "^Filesystem" | while read fs total used avail perc mount; do
  echo "$fs"
  echo "        $avail"
done

Resultado da execução:

$ ./exemplo.sh 
Sistema
        disponivel
/dev/mapper/system-root
        2014976
devtmpfs
        8121660
tmpfs
        8133648