Tutorial de Linux / Crie seu primeiro script Bash com variáveis, condições e repetições

Um script de shell reúne comandos e o fluxo de execução em um programa reutilizável. Para criar seu primeiro script Bash, proteja as expansões de variáveis com aspas, valide os argumentos e confira o estado de saída ao testar cada comportamento.

Nesta aula, você cria e executa um programa salvo em arquivo. Consulte o fluxo de execução do shell para revisar variáveis e operadores; a aula sobre erros no Bash e operações seguras com arquivos, em inglês aprofunda as limitações relacionadas a falhas, caminhos e execução simultânea.

Escolha o Bash e prepare uma pasta de trabalho

O exercício foi escrito para Bash no Ubuntu e no Rocky Linux. Recursos como [[ ... ]] e arrays não funcionam necessariamente em outros interpretadores sh; por isso, não execute um script Bash com sh script.sh. Confira a instalação com bash --version e salve os arquivos com quebras de linha LF.

Execute as linhas abaixo na mesma sessão, em ordem, e pare se alguma falhar. Após mktemp, confirme que lab contém uma nova pasta dentro do seu diretório pessoal; só prossiga depois de cd entrar nela. Se a criação ou a mudança de pasta falhar, não execute as gravações seguintes em outro local.

lab=$(mktemp -d "$HOME/linux-script-lab.XXXXXX")
cd "$lab"
mkdir "sample files"
printf "one\n" > "sample files/alpha.txt"
printf "two\n" > "sample files/beta.txt"

Crie um script completo e executável

O bloco abaixo cria list-files.sh na pasta atual. O programa recebe um argumento, verifica se ele indica um diretório e imprime os nomes dos arquivos regulares desse diretório. O próprio programa de listagem não cria nem exclui arquivos; a preparação do exercício cria os arquivos de exemplo. A pasta nova evita sobrescrever um script que já existia.

cat > list-files.sh <<'EOF'
#!/usr/bin/env bash
if (( $# != 1 )); then
  printf "Usage: %s DIRECTORY\n" "$0" >&2
  exit 2
fi
directory=$1
if [[ ! -d "$directory" ]]; then
  printf "Not a directory: %s\n" "$directory" >&2
  exit 1
fi
count=0
for path in "$directory"/*; do
  [[ -f "$path" ]] || continue
  printf "%s\n" "${path##*/}"
  count=$((count + 1))
done
printf "files=%s\n" "$count"
EOF
bash -n list-files.sh
bash list-files.sh "sample files"

Espere alpha.txt, beta.txt e files=2; a ordem dos nomes pode variar conforme a localidade. bash -n verifica apenas a sintaxe, sem testar caminhos, permissões ou o resultado da execução. A primeira linha, iniciada por #!, é o shebang, que indica o interpretador quando o arquivo é executado diretamente.

As aspas em <<'EOF' preservam as variáveis no texto escrito: elas serão expandidas quando o script rodar, não enquanto ele é criado. A linha final EOF deve ficar sozinha, sem espaços antes ou depois.

Entenda as variáveis e as aspas nos caminhos

Escreva uma atribuição sem espaços ao redor do sinal de igual, como directory=$1. Ao usar o valor, "$directory" mantém um caminho com espaços em um único argumento. As aspas simples preservam o texto literal; as aspas duplas permitem a expansão de parâmetros do Bash, evitando a divisão em palavras e a expansão de nomes de arquivos no resultado. Não é necessário usar eval para interpretar novamente a entrada como comando.

Em "$directory"/*, a parte do diretório fica protegida, e apenas o asterisco participa da expansão de nomes. Na configuração padrão do Bash, um padrão sem correspondências pode permanecer literal; [[ -f "$path" ]] || continue ignora essa entrada. O padrão não inclui arquivos ocultos iniciados por ponto nem percorre subdiretórios. Um link simbólico para um arquivo regular também pode passar no teste -f.

Leia argumentos, condições, repetições e estados de saída

Sintaxe Significado
$# / $1 Quantidade de argumentos / primeiro argumento
[[ -d ... ]] Verifica se o destino é um diretório
for ...; do ...; done Executa o mesmo conjunto de comandos para cada item expandido
${path##*/} Remove o prefixo até a última barra, deixando somente o nome
exit 0 / 1 / 2 Sucesso / destino inválido / uso incorreto neste exemplo

Se o último printf for bem-sucedido, o script termina com estado 0. Os significados de 1 e 2 são convenções definidas por este programa, e não categorias universais para todos os comandos. $? contém o estado do comando imediatamente anterior; consulte-o antes de executar outro comando.

bash list-files.sh
printf "exit=%s\n" "$?"
bash list-files.sh missing-directory
printf "exit=%s\n" "$?"
chmod u+x list-files.sh
./list-files.sh "sample files"

A execução sem argumentos mostra Usage: na saída de erro e deve resultar em exit=2. O caminho inexistente mostra Not a directory: e deve resultar em exit=1. A última linha executa diretamente o programa com o diretório válido e deve listar os dois arquivos. Um estado 0 confirma o término do programa, mas este exemplo não detecta todos os problemas possíveis de leitura: ele não é uma auditoria completa de diretórios ou permissões.

Altere uma condição de cada vez e compare os resultados

  1. Execute bash list-files.sh "sample files" e confirme files=2.
  2. Crie apenas gamma.txt com printf "three\n" > "sample files/gamma.txt" e repita a execução: a contagem deve subir para 3.
  3. Remova somente o arquivo acrescentado com rm -- "sample files/gamma.txt" e execute novamente para confirmar a volta a 2.
  4. Crie empty-directory com mkdir empty-directory e passe esse nome ao script: espere files=0. Compare também com o caminho inexistente e seu estado 1.

Se aparecer um erro com bash\r ou ^M depois de editar no Windows, verifique as quebras de linha. bash ARQUIVO lê o script sem exigir o bit de execução; ./ARQUIVO precisa de permissão de execução, de um interpretador válido e de um sistema de arquivos que permita executar arquivos. Antes de limpar o exercício, confira a pasta atual e não use comandos de exclusão em massa em diretórios do sistema.

Se o editor indicar CRLF, altere para LF e salve. No VS Code, use o indicador CRLF da barra de status e escolha LF. Em um ambiente com GNU sed, o bloco a seguir cria uma cópia e converte somente o list-files.sh deste exercício. Se o backup já existir, cp -i pede confirmação antes de sobrescrevê-lo; preserve uma cópia correta antes de continuar.

cp -i -- list-files.sh list-files.sh.crlf-backup
sed -i 's/\r$//' list-files.sh
bash -n list-files.sh
bash list-files.sh "sample files"

A verificação de sintaxe deve terminar com estado 0 e sem saída. Se restarem apenas os dois arquivos originais, a execução deve informar files=2. Para desfazer a conversão, confira o conteúdo do backup e restaure-o com cp -i -- list-files.sh.crlf-backup list-files.sh. Se o backup contiver CRLF, restaurá-lo também traz essas quebras de linha de volta.

Referências oficiais