NoticiasLinux.com.br Notícias do Mundo GNU/Linux
13 de setembro de 2026 · por Redação

Bash script no Linux: o guia definitivo para automatizar tarefas (do zero)

Aprenda a criar bash scripts no Linux do zero: shebang, variáveis, condicionais, loops, funções e agendamento com cron. Guia prático de automação para iniciantes.

Todo mundo que usa Linux por tempo suficiente chega ao mesmo momento de epifania: "eu já digitei essa mesma sequência de comandos umas cinquenta vezes esta semana". Fazer backup de uma pasta, atualizar o sistema, renomear cem arquivos, verificar se um serviço caiu — tarefas que você repete no terminal até a memória muscular assumir. O bash script existe exatamente para acabar com essa repetição: você escreve os comandos uma vez, num arquivo de texto, e a máquina os executa por você quantas vezes quiser, na ordem certa, sem erro de digitação e — se quiser — às três da manhã enquanto você dorme. Este guia parte absolutamente do zero e te leva até escrever scripts úteis de verdade: variáveis, decisões, repetições, funções e agendamento automático. No fim, o terminal deixa de ser um lugar onde você trabalha e vira um lugar onde você manda o trabalho ser feito.

O que é o shell e o que é o Bash

Quando você abre um terminal no Linux e digita um comando, quem lê aquilo e devolve uma resposta é um programa chamado shell — o interpretador de comandos. Você digita ls, ele lista os arquivos; você digita algo inválido, ele reclama com uma mensagem de erro. Esse vaivém de "você pede, ele responde" é a essência do shell.

O shell mais comum no mundo Linux se chama Bash (de Bourne Again Shell). Para descobrir qual shell você está usando agora, rode:

echo $SHELL

Na maioria das distribuições, a resposta será /bin/bash. Existem outros shells igualmente válidos, como o zsh e o fish, mas o Bash é o padrão de fato — está presente em praticamente todo servidor Linux do planeta, e é por isso que aprender a escrever scripts em Bash é uma habilidade que nunca envelhece.

Uma coisa importante para ajustar a mentalidade: o Bash é, na prática, quase uma linguagem de programação. Ele tem variáveis, condicionais (if), laços de repetição (for, while) e tudo o que se espera de uma linguagem. Tecnicamente ele é um interpretador de comandos, não uma linguagem "de verdade" como Python — mas, para os nossos fins, você vai programar. E a boa notícia é que, como cada linha de um script é apenas um comando que você já poderia digitar no terminal, você já sabe metade da matéria só de usar o Linux no dia a dia.

Por que automatizar

Na sua forma mais básica, um shell script é uma maneira de executar uma série de comandos em sequência. Você junta vários comandos num arquivo de texto e, quando executa esse arquivo, o Bash roda cada linha na ordem, de cima para baixo, exatamente como se você as estivesse digitando uma a uma.

Vale uma dose de honestidade que os bons cursos sempre dão: um script só compensa se ele economiza seu tempo. Automatizar um único comando que você roda uma vez por mês provavelmente dá mais trabalho do que simplesmente digitá-lo. O valor real aparece quando há muitos comandos encadeados, ou quando o script precisa tomar decisões (fazer uma coisa se o sistema for Ubuntu, outra se for Arch), ou quando você quer que algo rode sozinho, repetidamente, sem você por perto. É aí que o script deixa de ser um truque e vira uma ferramenta.

Seu primeiro script: "Hello World"

Vamos criar o clássico primeiro programa. Abra um editor de texto no terminal — o Nano é o mais amigável para começar:

nano meuscript.sh

Dentro do arquivo, escreva:

#!/bin/bash
echo "Hello World"

Salve com Ctrl+O (e Enter) e saia com Ctrl+X. Agora vamos entender cada pedaço, porque essas duas linhas contêm dois conceitos fundamentais.

O shebang

Aquela primeira linha, #!/bin/bash, tem um nome curioso: shebang (ou hashbang). Ela diz ao sistema qual interpretador deve executar o arquivo. Graças a ela, mesmo que o seu shell padrão seja o fish ou o zsh, este script específico será executado pelo Bash. Todo script bem escrito começa com um shebang, e ele é a única linha começada com # que o Bash não trata como comentário. A segunda linha, echo "Hello World", usa o comando echo, que simplesmente imprime na tela o texto que você passa.

Extensão .sh e permissão de execução

Reparou no .sh no nome do arquivo? Ele não é obrigatório — é apenas uma convenção que ajuda a identificar scripts de shell. No Linux, o que define se um arquivo é executável não é a extensão, e sim o shebang lá dentro e uma permissão de execução. Por padrão, um arquivo de texto recém-criado não pode ser executado; você precisa ligar esse "interruptor":

chmod +x meuscript.sh

O comando chmod +x adiciona a permissão de execução. Em muitas distribuições, depois disso o nome do arquivo aparece em verde quando você roda ls — um sinal visual de que ele virou executável. Agora é só rodar:

./meuscript.sh

Aquele ./ na frente diz ao Bash "execute o arquivo que está aqui neste diretório". A resposta será um belo Hello World na tela. Parabéns: você acabou de escrever e rodar seu primeiro bash script.

Comentários

Qualquer linha que comece com # (fora o shebang) é um comentário: o Bash a ignora completamente. Comentários servem para você (e para quem for ler o script depois) entender o que cada trecho faz:

#!/bin/bash
# Este script cumprimenta o usuário
echo "Hello World"

Parece bobagem agora, mas daqui a seis meses, quando você reabrir um script de trinta linhas, esses comentários valerão ouro.

Variáveis: guardando informação

Variáveis são caixinhas onde você guarda um valor para reutilizar. A atribuição em Bash tem uma regra que pega todo iniciante: não pode haver espaços em volta do sinal de igual.

nome="João"
idade=40

Escrever nome = "João" (com espaços) dá erro — memorize isso desde já. Para usar o valor guardado, você coloca um cifrão $ na frente do nome:

echo $nome

Sem o cifrão, echo nome imprimiria literalmente a palavra "nome". O $ é o que diz ao Bash "me dê o conteúdo desta variável". Uma variável que nunca foi declarada simplesmente vale vazio, sem gerar erro.

Aspas simples e aspas duplas

Aqui mora uma sutileza que vale entender cedo, porque confunde muita gente. Veja a diferença:

nome="João"
echo "Olá, meu nome é $nome"   # imprime: Olá, meu nome é João
echo 'Olá, meu nome é $nome'   # imprime: Olá, meu nome é $nome

Com aspas duplas, o Bash expande a variável, trocando $nome pelo valor. Com aspas simples, ele imprime tudo literalmente, sem expandir nada. A regra prática: use aspas duplas quando quiser que suas variáveis sejam substituídas pelo valor — que é quase sempre.

Variáveis de ambiente

O sistema já traz uma porção de variáveis prontas, chamadas variáveis de ambiente. Você não precisa declará-las — elas já existem na sua sessão. Algumas úteis:

echo $USER    # seu nome de usuário
echo $HOME    # o caminho da sua pasta pessoal
echo $PATH    # a lista de pastas onde o sistema procura programas

Para ver todas as variáveis de ambiente de uma vez, rode o comando env. Repare que os nomes delas são em MAIÚSCULAS — isso é uma convenção: reserve as maiúsculas para variáveis de ambiente e use minúsculas para as suas próprias variáveis. Nada obriga, mas seguir esse costume mantém seu código legível e evita confusão.

Guardando a saída de um comando

Um dos recursos mais poderosos do Bash é capturar a saída de um comando dentro de uma variável, usando a sintaxe $(...):

#!/bin/bash
nome="João"
agora=$(date)
echo "Olá, $nome"
echo "A data e hora do sistema são: $agora"

Aqui, $(date) executa o comando date e guarda o resultado na variável agora. Isso se chama substituição de comando, e é a cola que une comandos e lógica nos seus scripts. Outro exemplo: arquivos=$(ls) guarda a lista de arquivos do diretório na variável arquivos.

Recebendo dados: entrada e argumentos

Scripts ficam muito mais úteis quando reagem a informações de fora. Há duas formas principais de alimentá-los.

Lendo o que o usuário digita: read

O comando read pausa o script e espera o usuário digitar algo, guardando o resultado numa variável:

#!/bin/bash
echo "Por favor, digite o seu nome:"
read nome
echo "O seu nome é $nome"

Simples e interativo. Ótimo para scripts que conversam com quem os executa.

Argumentos de linha de comando

A outra forma é passar informações na hora de executar o script. Esses valores ficam disponíveis em variáveis especiais: $1 é o primeiro argumento, $2 o segundo, e assim por diante.

#!/bin/bash
echo "Você passou o argumento: $1"

Se você rodar ./meuscript.sh Linux, a saída será "Você passou o argumento: Linux". Existe também $#, que guarda quantos argumentos foram passados — perfeito para validar se o usuário usou o script corretamente:

#!/bin/bash
if [ $# -ne 1 ]; then
    echo "Uso: $0 <diretório>"
    exit 1
fi
echo "Você tem $(( $(ls -l $1 | wc -l) - 1 )) objetos em $1"

Esse trecho verifica se exatamente um argumento foi passado; se não (-ne 1, "diferente de 1"), mostra a forma correta de uso e encerra. Já entramos em território de condicionais — vamos formalizá-las.

Fazendo contas

Você não vai fazer matemática pesada em Bash com frequência, mas o básico é útil. Há duas formas comuns. A primeira é o comando expr:

expr 30 + 10      # 40
expr 100 \* 4     # 400 — o asterisco precisa da barra invertida

O detalhe do \*: no Bash, o asterisco sozinho significa "tudo" (curinga), então para multiplicar você precisa "escapá-lo" com a barra invertida. A segunda forma, mais moderna e limpa, é a expansão aritmética com $(( )):

numero=5
echo $(( numero + 1 ))   # 6

Foi essa a técnica que usamos no exemplo dos argumentos para subtrair 1 da contagem de linhas.

Tomando decisões: condicionais

Aqui o script ganha inteligência: ele passa a fazer coisas diferentes dependendo da situação. A estrutura é o if:

#!/bin/bash
numero=200
if [ $numero -eq 200 ]; then
    echo "A condição é verdadeira"
fi

Três detalhes cruciais. Primeiro, aqueles colchetes [ ] são, na verdade, um comando chamado test — e ele exige espaços por dentro: [ $numero -eq 200 ] funciona, [$numero -eq 200] não. Segundo, o bloco fecha com fi (que é "if" escrito ao contrário). Terceiro, aquele -eq é o operador de igualdade para números. Você pode adicionar o caminho alternativo com else:

if [ $numero -eq 200 ]; then
    echo "É igual a 200"
else
    echo "Não é igual a 200"
fi

Os operadores de comparação

Para comparar números, o Bash usa operadores de duas letras:

  • -eq — igual (equal)
  • -ne — diferente (not equal)
  • -gt — maior que (greater than)
  • -lt — menor que (less than)
  • -ge / -le — maior ou igual / menor ou igual

Também dá para testar arquivos e diretórios, o que é extremamente comum em automação:

if [ -f ~/meuarquivo ]; then
    echo "O arquivo existe"
else
    echo "O arquivo não existe"
fi

Aqui -f testa se um arquivo existe, e -d testa se um diretório existe. Um ponto de exclamação ! inverte qualquer teste: [ ! -f arquivo ] é verdadeiro quando o arquivo não existe.

Usando comandos como condição

Você não precisa dos colchetes se quiser testar se um comando teve sucesso. Um caso clássico é checar se um programa está instalado antes de usá-lo:

if command -v htop; then
    echo "O htop está disponível"
else
    sudo apt update && sudo apt install htop -y
fi

O command -v htop verifica se o comando existe. Repare no && na linha de instalação: ele encadeia comandos de modo que o segundo (apt install) só roda se o primeiro (apt update) tiver dado certo. Existe também o || (dois "pipes"), que funciona como "ou" dentro de uma condição:

if grep -q "Debian" /etc/os-release || grep -q "Ubuntu" /etc/os-release; then
    echo "Este é um sistema baseado em Debian ou Ubuntu"
fi

Muitas opções: o case

Quando há várias possibilidades, uma pilha de if/elif fica feia. Para isso existe o case, perfeito para menus:

#!/bin/bash
echo "Qual é a sua distribuição favorita?"
echo "1. Arch   2. Debian   3. Ubuntu"
read distro

case $distro in
    1)
        echo "Arch: para quem gosta de controle total"
        ;;
    2)
        echo "Debian: estabilidade lendária"
        ;;
    3)
        echo "Ubuntu: popular em desktops e servidores"
        ;;
    *)
        echo "Opção inválida"
        ;;
esac

Cada opção termina com ;; (dois ponto-e-vírgulas — esquecer isso quebra o case), o bloco fecha com esac ("case" ao contrário) e o *) é o curinga que captura qualquer coisa que não se encaixe nas opções anteriores.

Repetindo tarefas: loops

Loops são o coração da automação — é onde "faça isto para cada arquivo" acontece. O Bash tem dois principais.

O loop while

O while repete enquanto uma condição for verdadeira:

#!/bin/bash
contador=1
while [ $contador -le 10 ]; do
    echo $contador
    contador=$(( contador + 1 ))
    sleep 0.5
done

Ele conta de 1 a 10, incrementando a variável a cada volta e parando quando contador chega a 11 (aí -le 10 deixa de ser verdadeiro). O sleep 0.5 dá uma pausa de meio segundo entre as iterações. Um uso prático e engenhoso é vigiar um arquivo:

while [ -f ~/arquivo-importante ]; do
    echo "O arquivo ainda existe em $(date)"
    sleep 5
done
echo "O arquivo sumiu! Encerrando."

O loop for

O for percorre uma lista de itens, executando o bloco uma vez para cada um:

for numero in 1 2 3 4 5; do
    echo $numero
done

Digitar a lista à mão é chato; para sequências, use a notação de chaves {início..fim}:

for n in {1..10}; do
    echo $n
done

Mas o verdadeiro poder aparece ao iterar sobre arquivos. Este exemplo compacta todos os arquivos .log de uma pasta, um por um:

for arquivo in /var/log/*.log; do
    tar -czvf $arquivo.tar.gz $arquivo
done

O *.log casa com qualquer arquivo terminado em .log, e o loop aplica o tar (compactação) a cada um. Um trabalho que levaria muito tempo na mão vira três linhas.

Funções: organizando e reaproveitando

Quando um script cresce, você começa a repetir blocos de lógica. Funções resolvem isso, dando um nome a um pedaço de código que você pode chamar quantas vezes quiser:

#!/bin/bash

cumprimentar() {
    echo "Olá, $1! Bem-vindo."
}

cumprimentar "Maria"
cumprimentar "Pedro"

Definimos a função cumprimentar uma vez e a chamamos duas. Dentro dela, os argumentos funcionam igual aos do script: $1 é o primeiro valor passado na chamada. Duas boas práticas com funções: use local para criar variáveis que existem só dentro da função (evitando conflitos com o resto do script) e use return para devolver um código de status:

somar() {
    local resultado=$(( $1 + $2 ))
    echo $resultado
}

total=$(somar 5 3)
echo "A soma é $total"

Note que capturamos o que a função "imprime" com a mesma substituição de comando $(...) que já conhecemos. Funções tornam scripts longos legíveis e fáceis de manter.

Pipes, redirecionamento e código de saída

Estes três conceitos, herdados da filosofia Unix, multiplicam o que seus scripts conseguem fazer.

Os três fluxos e o redirecionamento

Todo comando tem três "canais": a entrada padrão (stdin, de onde ele lê), a saída padrão (stdout, o resultado normal) e a saída de erro (stderr, as mensagens de erro). Você pode desviar esses canais para arquivos:

ls > lista.txt      # grava a saída num arquivo (sobrescreve)
ls >> lista.txt     # acrescenta ao final do arquivo (append)
comando 2> erros.txt   # desvia só os erros para um arquivo

Um destino especialíssimo é o /dev/null, o "buraco negro" do sistema: tudo que você manda para lá é descartado. É ótimo para silenciar erros que não interessam:

find /etc -type f 2> /dev/null

Isso procura arquivos em /etc e joga fora todas as mensagens de "permissão negada", deixando só os resultados úteis.

Pipes

O pipe | conecta a saída de um comando à entrada de outro, criando correntes de processamento:

ls -l /etc | wc -l

Aqui, a listagem de /etc é "canalizada" para o wc -l, que conta as linhas. É assim que se montam operações complexas encaixando ferramentas simples.

O código de saída e o exit

Todo comando, ao terminar, devolve um código de saída: 0 significa sucesso, e qualquer outro número significa que algo deu errado. Esse código fica guardado na variável especial $?:

ls /etc
echo $?        # provavelmente 0 (deu certo)
ls /naoexiste
echo $?        # diferente de 0 (falhou)

Isso é ouro para scripts que rodam sozinhos: eles podem checar se um passo funcionou e reagir. Uma armadilha importante: $? reflete o último comando executado. Se você puser um echo antes de checá-lo, estará lendo o código do echo, não do comando que importa. Verifique $? imediatamente:

sudo apt install htop
if [ $? -eq 0 ]; then
    echo "Instalado com sucesso"
else
    echo "A instalação falhou"
fi

E o comando exit encerra o script na hora, com o código que você escolher: exit 0 para sucesso, exit 1 para erro. Qualquer linha depois de um exit alcançado nunca será executada.

Boas práticas que separam o amador do profissional

Alguns hábitos fazem enorme diferença na qualidade dos seus scripts:

  • Não se repita (DRY). Se um valor aparece em vários lugares, transforme-o numa variável. Muda num ponto, reflete em todos.
  • Evite prompts em scripts automáticos. Ao instalar pacotes, use -y (como em apt install htop -y) para responder "sim" automaticamente. Ninguém quer acordar às 3h da manhã porque o script parou esperando uma confirmação.
  • Ponha aspas nas variáveis. Usar "$arquivo" em vez de $arquivo evita que nomes com espaços quebrem o script — um dos bugs mais comuns em Bash.
  • Comece scripts sérios com set -euo pipefail. Essa linha, logo após o shebang, faz o script parar no primeiro erro (-e), reclamar de variáveis não definidas (-u) e detectar falhas no meio de um pipe. É uma rede de segurança poderosa.
  • Passe o código no ShellCheck. O software livre shellcheck analisa seu script e aponta erros e más práticas antes de você se queimar. Instale-o e use sempre.
  • Teste de verdade, inclusive simulando erros de propósito, especialmente quando seu script depende de códigos de saída.

Um exemplo completo: script de atualização universal

Vamos juntar tudo num script realmente útil — um que atualiza o sistema, seja ele qual for, detectando a distribuição automaticamente:

#!/bin/bash
arquivo_release=/etc/os-release

if grep -q "Arch" $arquivo_release; then
    sudo pacman -Syu
fi

if grep -q "Debian" $arquivo_release || grep -q "Ubuntu" $arquivo_release; then
    sudo apt update && sudo apt dist-upgrade -y
fi

O truque está no grep -q (o -q é de "quiet": ele não imprime nada, só devolve verdadeiro ou falso conforme encontre o texto). O script inspeciona o arquivo /etc/os-release, que identifica a distribuição, e executa o gerenciador de pacotes correto. Um único script que funciona em Arch, Debian e Ubuntu.

Onde guardar seus scripts (e como rodá-los de qualquer lugar)

Deixar scripts soltos na pasta pessoal funciona, mas não é o ideal. A convenção do Linux (o padrão FHS) recomenda colocar scripts que você quer usar em qualquer lugar dentro de /usr/local/bin:

sudo mv update.sh /usr/local/bin/update

Repare que removemos a extensão .sh — como o shebang já identifica o interpretador, a extensão é dispensável, e assim você digita só update para rodar. Isso funciona porque /usr/local/bin faz parte do $PATH, a lista de pastas onde o shell procura por programas. Verifique com echo $PATH. A partir daí, seu script se comporta como qualquer outro comando do sistema, chamável de onde você estiver.

Automação de verdade: agendando com o cron

O último passo para o script trabalhar sozinho é agendá-lo. O cron é o agendador de tarefas do Linux. Edite a sua tabela de agendamentos com:

crontab -e

Cada linha tem cinco campos de tempo seguidos do comando: minuto, hora, dia do mês, mês e dia da semana. Um asterisco * significa "qualquer valor". Por exemplo:

30 1 * * 5 /usr/local/bin/update

Isso roda o script update toda sexta-feira à 1h30 da manhã (minuto 30, hora 1, qualquer dia do mês, qualquer mês, dia 5 da semana = sexta). Com uma linha dessas, aquela tarefa que você fazia na mão toda semana passa a acontecer sozinha, para sempre. Se você administra servidores remotos, combine isso com o acesso por SSH e terá manutenção totalmente automatizada.

Conclusão

Você percorreu um caminho e tanto: do primeiro echo "Hello World" até scripts que tomam decisões, repetem tarefas, definem funções, tratam erros e rodam sozinhos no meio da madrugada. E o mais importante é perceber que nenhum desses conceitos é complicado isoladamente — o shebang, as variáveis, o if, o for, o código de saída. A mágica está em combiná-los, e essa é uma habilidade que se constrói na prática, um script de cada vez.

A melhor forma de fixar tudo isso é escolher uma chatice real da sua rotina — aquele backup manual, aquela limpeza de arquivos, aquela verificação repetitiva — e transformá-la num script. Vai dar errado algumas vezes, você vai esquecer um espaço nos colchetes ou um ;; no case, e está tudo bem: é assim que se aprende. Guarde seus scripts em /usr/local/bin, versione as ideias boas, e em pouco tempo você terá uma pequena coleção de ferramentas feitas sob medida para o seu jeito de trabalhar. O Bash transformou o terminal de um lugar onde você digita comandos num lugar onde você ensina a máquina a trabalhar por você. Bons scripts!

📬 Receba no seu e-mail As principais notícias de Linux e software livre, sem custo.
« todos os artigos