Aula 24: Shell Script — automatização de tarefas com Bash

Aula 24: Shell Script — automatização de tarefas com Bash

O domínio de Shell Script é, sem exagero, o divisor de águas entre um administrador de sistemas que opera manualmente e um profissional de infraestrutura que orquestra rotinas complexas com consistência, segurança e previsibilidade. Nesta vigésima quarta aula do curso Linux — Do Zero ao Avançado, você deixará de enxergar o terminal apenas como um espaço para digitação de comandos isolados e passará a compreendê-lo como uma verdadeira plataforma de desenvolvimento voltada à automação de tarefas. O Shell Script com Bash permite transformar sequências de comandos em programas executáveis, capazes de tomar decisões, repetir operações, tratar erros e interagir com o sistema operacional de forma programática.

Por que esse conhecimento é tão importante? No cotidiano de um profissional de TI, tarefas como backups, monitoramento de serviços, rotinas de limpeza, provisionamento de usuários e coleta de logs consomem tempo e estão sujeitas a erros humanos quando realizadas manualmente. Um Shell Script bem escrito elimina a variabilidade, garante padronização e permite que o administrador se concentre em atividades de maior valor. Em nossos projetos na JRT Technology Solutions, nossos especialistas utilizam diariamente scripts em Bash para automatizar desde deploys de aplicações até auditorias de segurança em servidores Ubuntu, Debian, CentOS e Rocky Linux, justamente porque a portabilidade e a onipresença do interpretador Bash tornam essa linguagem indispensável.

Ao longo desta aula, você vai aprender desde os fundamentos teóricos — como o interpretador processa um script e a importância do shebang — até a construção de scripts avançados com funções, tratamento de erros, logs estruturados e agendamento via cron. Mostraremos o passo a passo completo para instalar e configurar ferramentas auxiliares, como o ShellCheck, em distribuições baseadas em Debian e em Red Hat. Cada comando será exibido com sua saída esperada no terminal, para que você possa verificar se sua execução está correta em tempo real.

Os pré-requisitos para acompanhar esta aula são os conhecimentos adquiridos nas aulas anteriores do curso, especialmente manipulação de arquivos, permissões, variáveis de ambiente e editores de texto como vi ou nano. Não é necessário saber programar em outras linguagens, mas familiaridade com lógica básica — variáveis, condicionais e loops — facilitará a compreensão. Mesmo que você nunca tenha escrito um script antes, os exemplos desta aula foram desenhados para serem progressivos: iniciaremos com um script simples e evoluiremos até uma solução robusta e pronta para produção.

Ao final desta aula, você será capaz de criar Shell Scripts totalmente funcionais, atribuir permissões de execução, depurar erros comuns, validar a sintaxe com ferramentas especializadas, escrever logs profissionais e agendar execuções automáticas. Esse é um passo essencial para as próximas aulas, que tratarão de agendamento avançado com systemd timers e processamento de texto com expressões regulares. Prepare seu terminal, pois a prática começa agora.

O que você vai aprender nesta aula

Antes de colocarmos as mãos no teclado, é fundamental estabelecer com clareza os objetivos de aprendizagem. Esta aula foi estruturada para que cada seção construa uma camada de conhecimento sobre a anterior, do conceito mais básico à aplicação mais sofisticada. Você não apenas verá comandos isolados, mas entenderá o porquê de cada escolha técnica e como aplicá-la em cenários reais de infraestrutura.

  • Compreender o que é Shell Script e como o interpretador Bash executa scripts no Linux
  • Dominar a estrutura de um script: shebang, variáveis, argumentos, condicionais e loops
  • Aprender a criar, editar e conceder permissão de execução a scripts de forma padronizada
  • Instalar e configurar o ShellCheck em Ubuntu/Debian e CentOS/RHEL/Rocky Linux
  • Construir um script completo de backup com geração de arquivos compactados e timestamps
  • Desenvolver um script avançado com funções, tratamento de erros, logs e rotação de backups
  • Agendar a execução automática de scripts usando cron
  • Verificar a corretude do script com comandos de validação e interpretar saídas de erro
  • Corrigir os erros mais frequentes em Shell Script, como permissão negada e quebras de linha
  • Aplicar boas práticas de mercado utilizadas pela JRT Technology Solutions em ambientes corporativos

Pré-requisitos e Ambiente

Para executar todos os procedimentos desta aula, você precisará de um ambiente Linux com acesso a um terminal e privilégios de usuário comum. O interpretador Bash já vem instalado por padrão em praticamente todas as distribuições Linux, mas vamos conferir sua presença e versão na seção de verificação. Recomendamos que você utilize uma máquina virtual ou um servidor de testes para não comprometer sistemas em produção, especialmente ao executar scripts que manipulam diretórios e arquivos.

Esta aula cobre dois ecossistemas principais de distribuições Linux, justamente para que você possa reproduzir os passos independentemente da plataforma utilizada em sua organização. No lado Debian, trabalharemos com Ubuntu Server 22.04/24.04 e Debian 12. No lado Red Hat, utilizaremos CentOS Stream 9, RHEL 9 e Rocky Linux 9. Os comandos de instalação de pacotes adicionais, como o ShellCheck, serão apresentados para ambos os gerenciadores de pacotes: apt e dnf.

Você também precisará de um editor de texto no terminal, como nano, vim ou vi. Caso prefira, pode criar os arquivos de script utilizando o comando cat com heredoc, como faremos em nossos exemplos para garantir que o conteúdo seja exibido por completo. Ter um diretório dedicado para armazenar seus scripts, como ~/bin, é uma excelente prática e será parte do nosso passo a passo, pois facilita a organização e permite adicionar o diretório ao PATH para executar scripts de qualquer local do sistema.

Por fim, verifique se você possui permissão para instalar pacotes com sudo, caso ainda não tenha o ShellCheck instalado. Em servidores corporativos, como os que gerenciamos na JRT Technology Solutions, é comum que a instalação de pacotes seja feita por um administrador com privilégios elevados, mas os scripts em si devem ser executados com o menor privilégio necessário. Esse princípio de segurança será reforçado ao longo de toda a aula, pois um bom Shell Script não deve depender de permissões de root para tarefas rotineiras, a menos que seja estritamente necessário.

Fundamentos do Shell Script: interpretador, shebang e variáveis

Um Shell Script nada mais é do que um arquivo de texto contendo uma sequência de comandos que o shell interpreta e executa em ordem. A grande vantagem é que qualquer comando que você digita interativamente no terminal pode ser incorporado a um script, ganhando a capacidade de automação. O interpretador padrão na maioria das distribuições Linux é o Bash (Bourne Again Shell), localizado geralmente em /bin/bash. A primeira linha de um script deve indicar qual interpretador será usado para executá-lo; essa linha é conhecida como shebang e tem a forma #!/bin/bash ou, de forma mais portátil, #!/usr/bin/env bash. A segunda forma é recomendada porque localiza o Bash automaticamente a partir do PATH, aumentando a compatibilidade entre sistemas.

Após o shebang, o corpo do script contém os comandos, que podem ser tão simples quanto um echo ou tão complexos quanto funções com estruturas condicionais aninhadas. É crucial entender que cada linha é executada sequencialmente, a menos que estruturas de controle alterem o fluxo. O Bash oferece variáveis para armazenar valores, e a atribuição segue a sintaxe NOME=valor, sem espaços ao redor do sinal de igual. Para acessar o valor de uma variável, utiliza-se o símbolo $ antes do nome, como em $NOME. As variáveis podem conter strings, números, caminhos de arquivos e até mesmo a saída de comandos, utilizando a substituição $(comando).

Existem também variáveis especiais que todo script deve dominar. A variável $0 contém o nome do próprio script, enquanto $1, $2 e assim por diante armazenam os argumentos passados na linha de comando. A variável $# informa a quantidade de argumentos recebidos, e $@ expande todos os argumentos como uma lista. O código de saída do último comando executado fica disponível em $?, sendo 0 para sucesso e qualquer outro valor para falha. Esse conhecimento é a base para construir scripts que tomam decisões informadas sobre o ambiente.

Outro conceito fundamental é a expansão de variáveis com aspas. Em Bash, “$VAR” (aspas duplas) preserva o valor da variável como uma única palavra, mesmo que contenha espaços, enquanto ‘$VAR’ (aspas simples) trata o conteúdo literalmente, sem expandir a variável. O uso correto de aspas evita uma infinidade de erros sutis, como a quebra de caminhos com espaços ou a interpretação acidental de caracteres especiais. Em nossos treinamentos na JRT Technology Solutions, enfatizamos que a ausência de aspas é uma das causas mais comuns de bugs em scripts que operam em ambientes reais.

Além das variáveis, o Shell Script disponibiliza estruturas de teste extremamente úteis. O comando test, representado por [ ] ou [[ ]], permite verificar condições sobre arquivos, strings e números. Por exemplo, [ -d “$DIR” ] verifica se o diretório existe, [ -f “$ARQ” ] verifica se é um arquivo regular, e comparações de strings usam operadores como = e !=. A tabela a seguir resume os operadores mais utilizados em scripts profissionais.

Tabela 1 — Principais operadores de teste em Shell Script
Operador Finalidade Exemplo de uso
-d DIR Verifica se o caminho é um diretório [ -d "/etc" ]
-f ARQ Verifica se o caminho é um arquivo regular [ -f "/etc/passwd" ]
-x ARQ Verifica se o arquivo tem permissão de execução [ -x "./backup.sh" ]
-z STR Verifica se a string é vazia [ -z "$VAR" ]
-n STR Verifica se a string não é vazia [ -n "$VAR" ]
= / != Compara strings (igualdade/diferença) [ "$USER" = "root" ]
-eq / -ne Compara números (igual/diferente) [ "$NUM" -eq 5 ]
-gt / -lt Compara números (maior/menor) [ "$IDADE" -gt 18 ]

Com esses fundamentos estabelecidos, você está pronto para criar seus primeiros scripts. Lembre-se de que a prática constante é essencial; à medida que avançarmos para as seções práticas, você verá esses conceitos aplicados em contextos reais de automação. A próxima seção aprofunda as estruturas de controle e os mecanismos de redirecionamento, que são o coração de qualquer Shell Script minimamente sofisticado.

Estruturas de Controle, Funções e Redirecionamentos no Shell Script

As estruturas de controle permitem que um Shell Script tome decisões e repita operações sem intervenção humana. O if é a estrutura condicional mais básica: ele avalia um comando ou teste e, se o resultado for verdadeiro (código de saída 0), executa um bloco de comandos. O else e o elif ampliam essa lógica para múltiplos cenários. Por exemplo, um script pode verificar se um serviço está ativo e, caso não esteja, tentar iniciá-lo e registrar um log. A sintaxe básica é if [ condição ]; then … fi, e é obrigatório fechar o bloco com fi.

Os loops for e while são as principais estruturas de repetição. O for itera sobre uma lista de itens, como arquivos de um diretório ou valores separados por espaços. O while executa um bloco enquanto uma condição permanecer verdadeira, sendo ideal para ler linha a linha de um arquivo ou monitorar processos. Além disso, o case oferece uma forma elegante de tratar múltiplos valores de uma variável, muito útil para construir menus e analisar flags de linha de comando, como veremos no script avançado desta aula.

As funções são blocos de código reutilizáveis que podem ser chamados pelo nome. Elas melhoram a legibilidade do script e evitam duplicação de código. Uma função é definida com a sintaxe nome_da_funcao() { … } ou function nome_da_funcao { … }. Dentro das funções, os argumentos são acessados pelas variáveis $1, $2 etc., que são locais à função. O retorno de uma função pode ser um código numérico por meio do comando return, permitindo que o chamador verifique sucesso ou falha com if.

O redirecionamento de entrada e saída é outro pilar essencial. Os operadores >, >> e < permitem enviar a saída de um comando para um arquivo, anexar ao final de um arquivo existente ou ler a entrada a partir de um arquivo, respectivamente. Os descritores de arquivo padrão são 0 (stdin), 1 (stdout) e 2 (stderr). Redirecionar 2>&1 envia a saída de erros para o mesmo destino da saída padrão, técnica comum em logs. Outro recurso poderoso é o pipe (|), que conecta a saída de um comando à entrada de outro, como em ps aux | grep nginx.

A combinação dessas estruturas viabiliza a criação de scripts que não apenas executam comandos, mas que reagem ao ambiente, tratam falhas e produzem registros auditáveis. Nas próximas seções, você verá como aplicar esses conceitos em exemplos concretos. Antes, porém, vamos instalar ferramentas complementares que elevarão a qualidade do seu Shell Script a padrões profissionais.

Instalando Ferramentas Complementares para Shell Script no Ubuntu/Debian e CentOS/RHEL

O interpretador Bash já vem instalado em todas as distribuições Linux modernas, mas uma ferramenta adicional que recomendamos fortemente é o ShellCheck. Trata-se de um analisador estático de scripts que identifica erros de sintaxe, más práticas, variáveis não declaradas, problemas com aspas e outros defeitos comuns. Em nossos projetos na JRT Technology Solutions, o ShellCheck faz parte do pipeline de validação de qualquer script que vá para produção, pois ele reduz drasticamente o tempo de depuração e previne falhas em ambientes críticos.

O processo de instalação é simples e será demonstrado para os dois principais gerenciadores de pacotes. Se você estiver usando Ubuntu ou Debian, o pacote está disponível nos repositórios oficiais. Execute os comandos abaixo para atualizar a lista de pacotes e instalar o ShellCheck com o apt. Em sistemas baseados em Red Hat, como CentOS Stream, RHEL e Rocky Linux, é necessário habilitar o repositório EPEL (Extra Packages for Enterprise Linux) antes de instalar com o dnf.

Passo 1 — Instalação no Ubuntu/Debian:

# Atualiza a lista de pacotes disponíveis no repositório
sudo apt update

# Instala o ShellCheck e suas dependências de forma não interativa
sudo apt install -y shellcheck

Passo 2 — Saída esperada após a instalação no Ubuntu/Debian:

Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Get:2 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  shellcheck
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 1.940 kB of archives.
After this operation, 12,8 MB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu jammy/universe amd64 shellcheck amd64 0.8.0-1 [1.940 kB]
Fetched 1.940 kB in 1s (1.900 kB/s)
Selecting previously unselected package shellcheck.
(Reading database ... 195642 files and directories currently installed.)
Preparing to unpack .../shellcheck_0.8.0-1_amd64.deb ...
Unpacking shellcheck (0.8.0-1) ...
Setting up shellcheck (0.8.0-1) ...
Processing triggers for man-db (2.10.2-1) ...

Passo 3 — Instalação no CentOS/RHEL/Rocky Linux:

# Habilita o repositório EPEL, necessário para pacotes adicionais no ecossistema Red Hat
sudo dnf install -y epel-release

# Instala o ShellCheck utilizando o gerenciador de pacotes dnf
sudo dnf install -y ShellCheck

Passo 4 — Saída esperada após a instalação no CentOS/RHEL/Rocky:

Last metadata expiration check: 0:03:22 ago on Wed 12 Aug 2026 10:15:44 AM -03.
Dependencies resolved.
================================================================================
 Package              Architecture   Version                  Repository    Size
================================================================================
 ShellCheck           x86_64         0.8.0-2.el9              epel         2.1 M
Installing dependencies:
 libffi               x86_64         3.4.2-8.el9              baseos        36 k

Transaction Summary
================================================================================
Install  2 Packages

Total download size: 2.2 M
Installed size: 12 M
Downloading Packages:
(1/2): libffi-3.4.2-8.el9.x86_64.rpm                 45 kB/s |  36 kB     00:00    
(2/2): ShellCheck-0.8.0-2.el9.x86_64.rpm             431 kB/s | 2.1 MB     00:05    
--------------------------------------------------------------------------------
Total                                               466 kB/s | 2.2 MB     00:05     
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1 
  Installing       : libffi-3.4.2-8.el9.x86_64                              1/2 
  Installing       : ShellCheck-0.8.0-2.el9.x86_64                          2/2 
  Running scriptlet: ShellCheck-0.8.0-2.el9.x86_64                          2/2 
  Verifying        : libffi-3.4.2-8.el9.x86_64                              1/2 
  Verifying        : ShellCheck-0.8.0-2.el9.x86_64                          2/2 
Installed:
  ShellCheck-0.8.0-2.el9.x86_64          libffi-3.4.2-8.el9.x86_64         
Complete!

Após a instalação, é recomendável criar um diretório padrão para armazenar seus scripts pessoais e adicioná-lo ao PATH. Dessa forma, você poderá executar seus scripts de qualquer lugar do sistema sem precisar digitar o caminho completo. O procedimento é idêntico em ambas as distribuições, pois depende apenas do shell e não do gerenciador de pacotes. Vamos executar os passos a seguir, que criam o diretório ~/bin, adicionam a linha de exportação ao arquivo ~/.bashrc e recarregam o arquivo para aplicar as alterações imediatamente.

# Cria o diretório ~/bin para armazenar scripts pessoais
mkdir -p "$HOME/bin"

# Adiciona o diretório ~/bin ao PATH no arquivo ~/.bashrc, preservando o conteúdo existente
echo 'export PATH="$HOME/bin:$PATH"' >> "$HOME/.bashrc"

# Recarrega as configurações do ~/.bashrc para o shell atual
source "$HOME/.bashrc"

# Exibe o novo valor do PATH para confirmar a inclusão do ~/bin
echo "$PATH"
/home/aluno/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

Com o diretório pronto e o ShellCheck instalado, você já pode armazenar e validar seus scripts como um profissional. Guarde essas informações, pois serão utilizadas nas próximas seções para criar e testar nossos exemplos de Shell Script. A instalação do ShellCheck é um investimento de poucos minutos que retornará em economia de horas de depuração futura.

Criando seu Primeiro Shell Script Completo — Automação de Backup

Vamos agora colocar em prática tudo o que foi aprendido até aqui criando um Shell Script de backup que compacta um diretório de origem e armazena o resultado em um diretório de destino com um timestamp no nome do arquivo. Esse script é um exemplo clássico e extremamente útil no cotidiano de qualquer administrador de sistemas. A ideia é que ele receba dois argumentos: o diretório de origem e o diretório de destino. Antes de criar o arquivo, entenda o raciocínio por trás de cada trecho, pois isso facilitará a adaptação para outros cenários.

O script começa com o shebang #!/usr/bin/env bash, que garante portabilidade entre sistemas onde o Bash pode estar em locais diferentes. Em seguida, utiliza-se set -euo pipefail para ativar um modo de segurança: -e faz o script encerrar imediatamente se qualquer comando retornar erro; -u considera o uso de variáveis não definidas como erro; e pipefail faz com que o código de saída de um pipeline seja o do primeiro comando que falhar, e não apenas o último. Essas opções são consideradas boas práticas e evitam que o script continue executando após uma falha silenciosa.

As duas primeiras variáveis capturam os argumentos usando a sintaxe ${1:?mensagem}, que atribui o valor do primeiro argumento e, se ele estiver vazio, imprime a mensagem de erro e encerra o script. Em seguida, o script valida se o diretório de origem existe com [ ! -d “$ORIGEM” ]. Se não existir, exibe uma mensagem de erro e sai com código 1, indicando falha. A criação do diretório de destino é feita com mkdir -p, que cria diretórios aninhados se necessário, sem erro se já existirem.

O nome do arquivo de backup é gerado dinamicamente com a data e hora atuais, obtidas pelo comando date +%Y%m%d_%H%M%S. O comando tar -czf cria um arquivo compactado com gzip, utilizando o -C para mudar para o diretório pai antes de empacotar, evitando que o caminho absoluto fique gravado no arquivo. Por fim, o script exibe uma mensagem de sucesso com o caminho completo do arquivo gerado. Acompanhe abaixo o conteúdo completo do script que devemos criar.

Passo 1 — Criando o arquivo do script:

# Utiliza um heredoc para criar o arquivo backup.sh com todo o conteúdo do script
cat << 'EOF' > "$HOME/bin/backup.sh"
#!/usr/bin/env bash
# Script: backup.sh
# Descrição: Realiza backup de um diretório de origem para um diretório de destino.
# Uso: backup.sh <diretorio_origem> <diretorio_destino>

# Ativa modo de segurança: encerra em erro, trata variáveis não definidas e falhas em pipes
set -euo pipefail

# Captura e valida os argumentos obrigatórios
ORIGEM="${1:?Erro: informe o diretório de origem como primeiro argumento}"
DESTINO="${2:?Erro: informe o diretório de destino como segundo argumento}"

# Verifica se o diretório de origem existe e é acessível
if [ ! -d "$ORIGEM" ]; then
    echo "Erro: o diretório de origem '$ORIGEM' não existe." >&2
    exit 1
fi

# Cria o diretório de destino se ele ainda não existir
if [ ! -d "$DESTINO" ]; then
    mkdir -p "$DESTINO"
    echo "Diretório de destino '$DESTINO' criado."
fi

# Gera um timestamp para compor o nome do arquivo de backup
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

# Monta o nome do arquivo com base no diretório de origem e no timestamp
NOME_ARQUIVO="backup_$(basename "$ORIGEM")_${TIMESTAMP}.tar.gz"
CAMINHO_SAIDA="${DESTINO}/${NOME_ARQUIVO}"

# Cria o arquivo compactado usando tar com gzip
# O -C faz o tar mudar para o diretório pai antes de empacotar,
# garantindo que apenas o nome do diretório original seja gravado.
tar -czf "$CAMINHO_SAIDA" -C "$(dirname "$ORIGEM")" "$(basename "$ORIGEM")"

# Exibe mensagem de sucesso com o caminho do arquivo gerado
echo "Backup concluído com sucesso: $CAMINHO_SAIDA"
EOF

Passo 2 — Concedendo permissão de execução ao script:

# Adiciona a permissão de execução para o dono do arquivo
chmod +x "$HOME/bin/backup.sh"

# Lista o arquivo para confirmar a permissão de execução (o -rwxr-xr-x indica sucesso)
ls -l "$HOME/bin/backup.sh"
-rwxr-xr-x 1 aluno aluno 1242 ago 12 10:30 /home/aluno/bin/backup.sh

Passo 3 — Executando o script e verificando o backup gerado:

# Executa o script passando /etc como origem e /tmp/backup como destino
"$HOME/bin/backup.sh" /etc /tmp/backup
Diretório de destino '/tmp/backup' criado.
Backup concluído com sucesso: /tmp/backup/backup_etc_20260812_103015.tar.gz

O script funcionou exatamente como esperado: criou o diretório de destino, compactou o diretório /etc e gerou um arquivo com timestamp no nome. Esse é o primeiro passo para dominar a arte da automação com Shell Script. Na próxima seção, evoluiremos esse exemplo para um script avançado com funções, tratamento granular de

Quer aprender na prática com especialistas?

A JRT Technology Solutions oferece treinamentos e implementação de Linux para equipes corporativas.



Falar no WhatsApp

Thiago Paes Rodrigues

Com mais de 22 anos de experiência em Tecnologia da Informação, este profissional construiu uma trajetória sólida como empresário, atuando de forma estratégica na implementação de soluções tecnológicas que otimizam processos e impulsionam resultados em diferentes setores.