Linux: Fundamentos de Script Bash
Salve uma sequência de comandos Linux em um arquivo, adicione um pouco de lógica (condições, laços) e você tem um Shell script. É o ponto de partida para automatizar todo trabalho repetitivo.
📋 Pré-requisitos: Você já deve conhecer
- Aula 19: Compactação e Arquivamento
1. O Que Você Vai Aprender
- Shebang e permissão de execução
- Definição de variáveis e diferenças entre aspas
- Parâmetros posicionais
- Lógica condicional com if/test
- Laços for/while
2. A História do Deploy Manual ao Deploy em Um Clique
(1) O Problema: Digitar as Mesmas 5 Comandos Todo Dia
Xiaoming precisava rodar esses comandos todo dia para fazer deploy: git pull, npm install, npm run build, pm2 restart app, echo "done". 5 comandos, 3 minutos, todo dia.
(2) Um Script de 8 Linhas
Ele escreveu um deploy.sh:
#!/bin/bash
set -e
echo "Starting deployment..."
cd /var/www/myapp
git pull origin main
npm install
npm run build
pm2 restart app
echo "✅ Deployment complete!"
set -e é a primeira linha de defesa para a segurança do script — o script para imediatamente se algum comando retornar código de saída diferente de zero. Sem set -e, o script continua rodando mesmo depois de uma falha, o que pode causar erros em cascata sérios (como reiniciar um serviço com código quebrado).
(3) O Benefício: Deploy em Um Clique
A partir daí, Xiaoming só precisava rodar ./deploy.sh — todas as etapas aconteciam automaticamente, economizando tempo e evitando esquecimentos.
3. Pontos-Chave
(1) Shebang
A primeira linha de um script precisa ser o Shebang — diz ao sistema qual interpretador usar:
#!/bin/bash # Executa com bash
#!/bin/sh # Executa com sh (modo de compatibilidade)
#!/usr/bin/env python3 # Executa com Python 3
#!/bin/bash é o Shebang — ele diz ao SO qual interpretador usar para rodar o script. Sem essa linha, o sistema usa o shell atual, o que pode causar problemas de compatibilidade (por exemplo, sh não aceita a sintaxe [[ ]]). Todo script bash precisa começar com #!/bin/bash.
(2) Variáveis
# Definir variáveis (sem espaço ao redor do igual)
name="Alice"
age=25
# Usar variáveis (chaves são recomendadas)
echo $name # Alice
echo ${name} # Alice (chaves são mais seguras)
echo "Hello, ${name}"
# Regras de nomes de variáveis
# 1. Letras, dígitos, sublinhado
# 2. Não pode começar com dígito
# 3. Sensível a maiúsculas/minúsculas (NAME != name)
Três Tipos de Aspas:
| Aspas | Exemplo | Comportamento |
|---|---|---|
| Aspas duplas | "Hello $name" |
Interpreta variáveis e comandos |
| Aspas simples | 'Hello $name' |
String literal, sem interpretação |
Crase/$() |
`date` ou $(date) |
Executa o comando e captura a saída |
ℹ️ Nota: A diferença essencial entre aspas simples e duplas — dentro das aspas duplas,
$variavele$(comando)são interpretados e substituídos; tudo dentro de aspas simples é literal. Use aspas duplas quando quiser interpolar variáveis, e aspas simples quando precisar manter$e outros caracteres especiais (por exemplo, em padrões de regex ou em heredocs onde você não quer expansão de variáveis).
name="Alice"
echo "Hello $name" # Hello Alice
echo 'Hello $name' # Hello $name
echo "Today is $(date)" # Today is Tue Jul 7 10:23:45 CST 2026
(3) Parâmetros Posicionais
./script.sh arg1 arg2 arg3
# $1 $2 $3
$0 # Nome do próprio script
$1, $2 # 1º, 2º argumento
$# # Quantidade de argumentos
$@ # Todos os argumentos (como palavras separadas)
$* # Todos os argumentos (como uma string única)
$? # Código de saída do comando anterior (0=sucesso, !=0=falha)
$$ # PID do script atual
(4) Lógica Condicional (if / test / [[ ]])
# Comando test ou [ ]
if [ "$name" = "Alice" ]; then
echo "Hello Alice"
fi
# [[ ]] é mais poderoso (específico do bash)
if [[ "$name" == "Alice" ]]; then
echo "Hello Alice"
fi
# if-elif-else
if [ "$1" -gt 10 ]; then
echo "Maior que 10"
elif [ "$1" -gt 5 ]; then
echo "Maior que 5"
else
echo "5 ou menos"
fi
Testes de Arquivo:
| Condição | Significado |
|---|---|
-f arquivo |
É um arquivo regular |
-d dir |
É um diretório |
-e caminho |
Existe |
-s arquivo |
Tamanho do arquivo > 0 |
-r arquivo |
É legível |
-w arquivo |
É gravável |
-x arquivo |
É executável |
Comparação de Strings:
| Condição | Significado |
|---|---|
$a = $b |
Igual |
$a != $b |
Diferente |
-z $a |
String vazia (tamanho = 0) |
-n $a |
String não vazia |
Comparação Numérica:
| Condição | Significado |
|---|---|
$a -eq $b |
Igual |
$a -ne $b |
Diferente |
$a -gt $b |
Maior que |
$a -ge $b |
Maior ou igual |
$a -lt $b |
Menor que |
$a -le $b |
Menor ou igual |
(5) Laços
# Laço for
for i in 1 2 3 4 5; do
echo "Number: $i"
done
for file in *.txt; do
echo "Found file: $file"
done
for i in {1..10}; do
echo "$i"
done
# Laço while
count=1
while [ $count -le 5 ]; do
echo "Attempt $count"
count=$((count + 1))
done
# Lê um arquivo linha por linha
while IFS= read -r line; do
echo "$line"
done < /etc/hostname
(6) ▶ Exemplo: Script Básico
#!/bin/bash
# hello.sh - Primeiro script bash
echo "Hello, World!"
echo "Current user: $(whoami)"
echo "Current directory: $(pwd)"
echo "File count: $(ls | wc -l)"
Saída:
TEXTHello, World! Current user: alice Current directory: /home/alice File count: 12
(7) ▶ Exemplo: Usando Parâmetros Posicionais
#!/bin/bash
# greet.sh - Saúda um usuário informado
if [ $# -eq 0 ]; then
echo "Usage: $0 <username>"
exit 1
fi
echo "Hello, $1!"
echo "Welcome to Linux scripting."
echo "Script name: $0"
echo "Argument count: $#"
./greet.sh Alice
# Hello, Alice!
(8) ▶ Exemplo: if Condicional
#!/bin/bash
# check-file.sh - Verifica o estado de um arquivo
FILE="${1:-test.txt}"
if [ ! -e "$FILE" ]; then
echo "File '$FILE' does not exist"
exit 1
fi
if [ -f "$FILE" ]; then
echo "Type: Regular file"
elif [ -d "$FILE" ]; then
echo "Type: Directory"
fi
[ -r "$FILE" ] && echo "Readable: ✅" || echo "Readable: ❌"
[ -w "$FILE" ] && echo "Writable: ✅" || echo "Writable: ❌"
[ -x "$FILE" ] && echo "Executable: ✅" || echo "Executable: ❌"
(9) ▶ Exemplo: Operação em Lote com Laço for
#!/bin/bash
# rename.sh - Renomeia em lote .txt para .md
count=0
for file in *.txt; do
if [ -f "$file" ]; then
mv "$file" "${file%.txt}.md"
echo "Renamed: $file → ${file%.txt}.md"
count=$((count + 1))
fi
done
echo "Total files renamed: $count"
(10) ▶ Exemplo: Laço while e Leitura de Entrada
#!/bin/bash
# countdown.sh - Timer de contagem regressiva
if [ $# -ne 1 ]; then
echo "Usage: $0 <seconds>"
exit 1
fi
count=$1
while [ $count -gt 0 ]; do
echo "Countdown: $count"
count=$((count - 1))
sleep 1
done
echo "Time's up!"
(11) ▶ Exemplo Abrangente: Script de Processamento em Lote
#!/bin/bash
# batch-process.sh - Processa em lote os arquivos de um diretório
DIR="${1:-.}"
ACTION="${2:-info}"
if [ ! -d "$DIR" ]; then
echo "Error: Directory '$DIR' does not exist"
exit 1
fi
echo "Processing directory: $DIR"
echo "Action: $ACTION"
echo "---"
case "$ACTION" in
info)
echo "File statistics:"
echo " Total files: $(find "$DIR" -type f | wc -l)"
echo " Total directories: $(find "$DIR" -type d | wc -l)"
echo " Total size: $(du -sh "$DIR" | cut -f1)"
;;
backup)
BACKUP="/tmp/backup-$(date +%Y%m%d)"
mkdir -p "$BACKUP"
cp -r "$DIR" "$BACKUP/"
echo "Backup complete: $BACKUP"
;;
clean)
echo "Cleaning .log files..."
find "$DIR" -name "*.log" -delete
echo "Cleaning .tmp files..."
find "$DIR" -name "*.tmp" -delete
echo "Cleaning complete"
;;
*)
echo "Actions: info / backup / clean"
;;
esac
❓ Perguntas Frequentes
P: O
#!/bin/bashna primeira linha é obrigatório? R: Sim. Ele diz ao kernel qual interpretador usar. Sem ele, o padrão é o shell atual (o que pode causar problemas de compatibilidade).
P: Por que meu script diz
command not found? R: Dois motivos: 1) Falta de permissão de execução — rodechmod +x script.sh. 2) O diretório atual não está no PATH — use./script.shem vez descript.sh.
P: Qual a diferença entre
$@e$*? R:$@trata cada argumento como uma "palavra" separada;$*junta todos os argumentos em uma única string. Na maioria dos cenários, recomenda-se$@. Iterar comfor arg in "$@"; doé a prática padrão.
P: Qual a diferença entre
exit 0eexit 1? R:exit 0significa sucesso;exitcom valor diferente de zero significa falha (números diferentes indicam tipos diferentes de erro). Outros programas podem verificar$?para saber se o script deu certo.
P: Como ler a entrada do usuário em um script? R: Use o comando
read:read -p "Digite seu nome: " nome, depois$nomeguarda o que o usuário digitou.
📖 Resumo
- Shebang
#!/bin/bash,chmod +xdá permissão de execução - Variáveis:
name="value", referencie com$nameou${name} - Aspas duplas interpretam variáveis, aspas simples são literais,
$(cmd)executa um comando if [ condição ]para lógica condicional,for i in listapara laçosexit 0para sucesso,exit 1para erro
📝 Exercícios
- Básico (⭐): Escreva um script
info.shque exiba o nome do usuário atual, a data, o diretório atual e a contagem de arquivos - Intermediário (⭐⭐): Escreva um script
check-file.shque receba o nome de um arquivo como argumento, verifique se ele existe e exiba seu tipo. Depois escreva um scriptbackup-txt.shque faça backup de todos os arquivos.txtdo diretório atual em/tmp/txt-backup/ - Avançado (⭐⭐⭐): Escreva um script de contagem regressiva que receba os segundos como argumento e conte um por segundo, adicionando tratamento de erro com
set -e. Em seguida, use um laçoforpara criar 10 diretórios detest-1atest-10, e por fim escreva um script que calcule e ordene os tamanhos desses 10 diretórios