Introducao ao Shell Script

Iniciante | 60 min leitura | 2025.12.02

O que voce vai aprender neste tutorial

  • Estrutura basica de shell scripts
  • Como usar variaveis
  • Condicionais (if)
  • Loops (for, while)
  • Scripts praticos de automacao

O que e Shell Script? Por que aprender?

A origem do Shell Script

A historia do shell script remonta a 1971 com o Thompson shell (sh). Em 1979, Stephen Bourne desenvolveu o Bourne Shell (sh), que se tornou a base dos shell scripts modernos.

Em 1989, Brian Fox desenvolveu o Bash (Bourne Again Shell) como parte do projeto GNU. Bash e atualmente o shell mais amplamente utilizado.

“Shell script e a forma mais simples de automatizar tarefas repetitivas” — Sabedoria antiga do ambiente Unix

Por que aprender Shell Script

  1. Automacao: Automatize tarefas repetitivas e economize tempo
  2. Administracao de sistemas: Essencial para gerenciamento de servidores, deploy e backup
  3. CI/CD: Amplamente usado no GitHub Actions, Jenkins, etc.
  4. Portabilidade: Funciona em praticamente todos os sistemas Unix

Bash e outros Shells

ShellCaracteristicasUso principal
bashMais difundido. Compativel com POSIX + extensoesScripts gerais
shPadrao POSIX. Funcionalidade minimaScripts com foco em portabilidade
zshCompativel com bash + autocompletar poderosoShell interativo
fishAmigavel ao usuarioShell interativo
dashLeve e rapidoScripts de sistema

Melhores praticas: Use #!/bin/sh para portabilidade, e #!/bin/bash quando usar recursos especificos do Bash.

Seu primeiro Shell Script

Vamos comecar com o “Hello World”.

hello.sh

#!/bin/bash

# Este e meu primeiro shell script
echo "Hello, World!"

Como executar

# Dar permissao de execucao
chmod +x hello.sh

# Executar
./hello.sh

# Ou especificar bash explicitamente
bash hello.sh

Sobre o Shebang

A primeira linha #!/bin/bash e chamada de shebang e especifica qual interpretador vai executar o script.

#!/bin/bash     # Executar com bash
#!/bin/sh       # Executar com POSIX sh (mais portavel)
#!/usr/bin/env bash  # Procurar bash no PATH e executar (recomendado)

Documentacao oficial: GNU Bash Manual

Como usar variaveis

Variaveis basicas

#!/bin/bash

# Definir variaveis (sem espacos ao redor do =!)
name="Joao"
age=25

# Referenciar variaveis
echo "Nome: $name"
echo "Idade: ${age} anos"

# Atribuir resultado de comando a uma variavel
current_date=$(date +%Y-%m-%d)
echo "Data de hoje: $current_date"

# Forma antiga (crase) - nao recomendado
old_style=`date +%Y-%m-%d`

Erro comum: Espacos

# Errado (espacos causam erro)
name = "Joao"    # command not found: name
name= "Joao"     # Variavel vazia como comando "Joao" executado

# Correto
name="Joao"

Escopo de variaveis

#!/bin/bash

# Variavel global
global_var="I am global"

function example() {
    # Variavel local (valida apenas dentro da funcao)
    local local_var="I am local"
    echo "$local_var"
    echo "$global_var"
}

example
echo "$local_var"   # Vazio (nao visivel fora da funcao)

Variaveis especiais

#!/bin/bash

echo "Nome do script: $0"
echo "Primeiro argumento: $1"
echo "Segundo argumento: $2"
echo "Numero de argumentos: $#"
echo "Todos os argumentos: $@"
echo "Todos os argumentos (string): $*"
echo "Status de saida do ultimo comando: $?"
echo "PID do processo atual: $$"
echo "PID do processo em background: $!"

Exemplo de execucao:

$ ./script.sh arg1 arg2 arg3
Nome do script: ./script.sh
Primeiro argumento: arg1
Segundo argumento: arg2
Numero de argumentos: 3
Todos os argumentos: arg1 arg2 arg3

Variaveis de ambiente

# Referenciar variaveis de ambiente
echo "Diretorio home: $HOME"
echo "Nome do usuario: $USER"
echo "Diretorio atual: $PWD"
echo "Shell: $SHELL"
echo "Path: $PATH"

# Definir variavel de ambiente (herdada por subprocessos)
export MY_VAR="some value"

# Definir variavel de ambiente temporariamente para executar comando
DEBUG=true ./my_script.sh

Diferenca entre aspas

name="World"

# Aspas duplas: variaveis sao expandidas
echo "Hello, $name"    # Hello, World

# Aspas simples: literal
echo 'Hello, $name'    # Hello, $name

# Escape com barra invertida
echo "Hello, \$name"   # Hello, $name

Condicionais (if)

Sintaxe basica

#!/bin/bash

age=20

if [ $age -ge 20 ]; then
    echo "E adulto"
elif [ $age -ge 13 ]; then
    echo "E adolescente"
else
    echo "E crianca"
fi

Tipos de sintaxe de teste

# [ ] - Sintaxe test classica (compativel com POSIX)
if [ $a -eq $b ]; then

# [[ ]] - Sintaxe estendida do Bash (recomendada)
if [[ $a == $b ]]; then

# (( )) - Avaliacao aritmetica
if (( a > b )); then

Melhores praticas: Ao usar Bash, recomenda-se [[ ]]. Permite pattern matching e expressoes regulares.

Operadores de comparacao numerica

OperadorSignificadoExemplo
-eqIgual (equal)[ $a -eq $b ]
-neDiferente (not equal)[ $a -ne $b ]
-ltMenor que (less than)[ $a -lt $b ]
-leMenor ou igual (less or equal)[ $a -le $b ]
-gtMaior que (greater than)[ $a -gt $b ]
-geMaior ou igual (greater or equal)[ $a -ge $b ]

Comparacao de strings

#!/bin/bash

str="hello"

# Comparacao de strings (importante usar aspas!)
if [ "$str" = "hello" ]; then
    echo "Strings sao iguais"
fi

# Verificar string vazia
if [ -z "$str" ]; then
    echo "String esta vazia"
fi

# Verificar se nao esta vazia
if [ -n "$str" ]; then
    echo "String nao esta vazia"
fi

# Pattern matching com [[ ]]
if [[ "$str" == h* ]]; then
    echo "Comeca com h"
fi

# Expressao regular (Bash 3.0+)
if [[ "$str" =~ ^[a-z]+$ ]]; then
    echo "Apenas letras minusculas"
fi

Verificacao de arquivos e diretorios

#!/bin/bash

# Verificar existencia de arquivo
if [ -f "config.txt" ]; then
    echo "config.txt existe"
fi

# Verificar existencia de diretorio
if [ -d "logs" ]; then
    echo "Diretorio logs existe"
fi

# Arquivo ou diretorio existe
if [ -e "path" ]; then
    echo "path existe"
fi

# Legivel
if [ -r "file.txt" ]; then
    echo "E legivel"
fi

# Gravavel
if [ -w "file.txt" ]; then
    echo "E gravavel"
fi

# Executavel
if [ -x "script.sh" ]; then
    echo "E executavel"
fi

# Arquivo nao esta vazio
if [ -s "file.txt" ]; then
    echo "Arquivo nao esta vazio"
fi

Operadores logicos

# AND
if [ $a -gt 0 ] && [ $a -lt 10 ]; then
    echo "0 < a < 10"
fi

# OR
if [ $a -eq 0 ] || [ $a -eq 1 ]; then
    echo "a is 0 or 1"
fi

# NOT
if [ ! -f "file.txt" ]; then
    echo "file.txt does not exist"
fi

# [[ ]] permite && e || internamente
if [[ $a -gt 0 && $a -lt 10 ]]; then
    echo "0 < a < 10"
fi

Instrucao case

Para multiplas condicoes, a instrucao case e conveniente:

#!/bin/bash

fruit="apple"

case $fruit in
    apple)
        echo "E uma maca"
        ;;
    banana|orange)
        echo "E banana ou laranja"
        ;;
    *)
        echo "Fruta desconhecida"
        ;;
esac

Loops

Loop for

#!/bin/bash

# Processar lista em ordem
for fruit in apple banana orange; do
    echo "Fruta: $fruit"
done

# Intervalo numerico (extensao Bash)
for i in {1..5}; do
    echo "Contagem: $i"
done

# Especificar incremento
for i in {0..10..2}; do
    echo "Par: $i"
done

# Estilo C
for ((i=0; i<5; i++)); do
    echo "Index: $i"
done

# Processar arquivos
for file in *.txt; do
    echo "Arquivo: $file"
done

# Processar saida de comando
for user in $(cat users.txt); do
    echo "Usuario: $user"
done

Loop while

#!/bin/bash

count=1
while [ $count -le 5 ]; do
    echo "Contagem: $count"
    count=$((count + 1))
done

# Ler arquivo linha por linha (padrao recomendado)
while IFS= read -r line; do
    echo "Linha: $line"
done < input.txt

# Loop infinito
while true; do
    echo "Press Ctrl+C to stop"
    sleep 1
done

Loop until

#!/bin/bash

count=1
until [ $count -gt 5 ]; do
    echo "Contagem: $count"
    count=$((count + 1))
done

Controle de loop

# break para sair do loop
for i in {1..10}; do
    if [ $i -eq 5 ]; then
        break
    fi
    echo $i
done

# continue para proxima iteracao
for i in {1..5}; do
    if [ $i -eq 3 ]; then
        continue
    fi
    echo $i
done

Definicao de funcoes

#!/bin/bash

# Definicao de funcao (duas formas)
function greet() {
    local name=$1
    echo "Ola, ${name}!"
}

# Ou
greet2() {
    echo "Hello, $1!"
}

# Chamar funcao
greet "Joao"
greet2 "World"

# Valor de retorno (status de saida)
is_even() {
    if (( $1 % 2 == 0 )); then
        return 0  # Sucesso (par)
    else
        return 1  # Falha (impar)
    fi
}

if is_even 4; then
    echo "4 e par"
fi

# Para retornar valor, use echo
add() {
    echo $(( $1 + $2 ))
}

result=$(add 3 5)
echo "3 + 5 = $result"

Pratica: Script de Backup

Usando o que aprendemos, vamos criar um script de backup pratico.

backup.sh

#!/bin/bash
#
# Script de backup automatico
# Uso: ./backup.sh [source_dir] [backup_dir]
#

set -euo pipefail  # Sair imediatamente em caso de erro

# Configuracao
SOURCE_DIR="${1:-./src}"
BACKUP_DIR="${2:-./backups}"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="backup_$DATE.tar.gz"
RETENTION_DAYS=7

# Funcao de log
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# Verificar/criar diretorio de backup
if [ ! -d "$BACKUP_DIR" ]; then
    log "Criando diretorio de backup..."
    mkdir -p "$BACKUP_DIR"
fi

# Verificar diretorio de origem
if [ ! -d "$SOURCE_DIR" ]; then
    log "Erro: $SOURCE_DIR nao encontrado"
    exit 1
fi

# Executar backup
log "Iniciando backup: $SOURCE_DIR -> $BACKUP_DIR/$BACKUP_NAME"
tar -czf "$BACKUP_DIR/$BACKUP_NAME" "$SOURCE_DIR"

if [ $? -eq 0 ]; then
    log "Concluido: $BACKUP_DIR/$BACKUP_NAME"
    log "Tamanho: $(du -h "$BACKUP_DIR/$BACKUP_NAME" | cut -f1)"
else
    log "Erro: Falha no backup"
    exit 1
fi

# Remover backups antigos
log "Removendo backups antigos (mais de ${RETENTION_DAYS} dias)..."
deleted=$(find "$BACKUP_DIR" -name "backup_*.tar.gz" -mtime +$RETENTION_DAYS -delete -print | wc -l)
log "Arquivos removidos: $deleted"

log "Tudo concluido!"

Melhores praticas para scripts

  1. Use set -euo pipefail

    • -e: Sair imediatamente em caso de erro
    • -u: Erro para variaveis indefinidas
    • -o pipefail: Detectar erros em pipes
  2. Sempre use aspas em variaveis: "$variable"

  3. Use funcoes: Melhor reusabilidade e legibilidade

  4. Adicione logs: Para debug e monitoramento

Tratamento de erros

#!/bin/bash

# Definir tratamento de erro com trap
cleanup() {
    echo "Executando limpeza..."
    # Remover arquivos temporarios, etc.
}

trap cleanup EXIT  # Executar ao sair do script
trap 'echo "Erro ocorrido: linha $LINENO"' ERR

# Ignorar erro se necessario
command_that_might_fail || true

# Tratamento alternativo em caso de erro
config_file="config.txt"
if [ -f "$config_file" ]; then
    source "$config_file"
else
    echo "Arquivo de configuracao nao encontrado. Usando valores padrao."
    default_value="fallback"
fi

Dicas de Debug

# Executar script inteiro em modo debug
bash -x script.sh

# Ativar debug dentro do script
set -x  # Iniciar debug
# ... codigo para debug ...
set +x  # Parar debug

# Sair imediatamente em caso de erro (recomendado)
set -e

# Erro para variaveis indefinidas (recomendado)
set -u

# Detectar erros em pipes (recomendado)
set -o pipefail

# Combinacao comum
set -euo pipefail

Analise estatica com ShellCheck

ShellCheck e uma ferramenta de analise estatica que detecta problemas em shell scripts.

# Instalacao
# macOS
brew install shellcheck

# Ubuntu/Debian
sudo apt install shellcheck

# Uso
shellcheck script.sh

Exemplos de problemas detectados pelo ShellCheck:

# Aviso: falta de aspas na variavel
echo $USER  # SC2086: Double quote to prevent globbing

# Corrigido
echo "$USER"

O Google Shell Style Guide tambem recomenda o uso do ShellCheck.

Padroes comuns

Validacao de argumentos

#!/bin/bash

if [ $# -lt 2 ]; then
    echo "Uso: $0 <source> <destination>"
    exit 1
fi

source=$1
destination=$2

Definicao de valores padrao

# Usar valor padrao se variavel nao definida ou vazia
name="${1:-World}"
echo "Hello, $name"

# Usar valor padrao apenas se variavel nao definida
name="${1-World}"

Criacao segura de arquivos temporarios

#!/bin/bash

# Usar mktemp (recomendado)
temp_file=$(mktemp)
temp_dir=$(mktemp -d)

# Remover ao sair
trap "rm -rf $temp_file $temp_dir" EXIT

echo "Arquivo temporario: $temp_file"
echo "Diretorio temporario: $temp_dir"

Obtendo entrada do usuario

#!/bin/bash

# Ler entrada
read -p "Digite seu nome: " name
echo "Ola, $name"

# Entrada de senha (oculta)
read -sp "Senha: " password
echo ""

# Com timeout
read -t 5 -p "Digite em 5 segundos: " input || echo "Timeout"

Proximos passos

Apos dominar o basico de shell script, avance para os proximos passos:

  • Expressoes regulares e grep, sed, awk
  • Execucao agendada com cron jobs
  • Automacao mais avancada (Ansible, Makefile, etc.)

Documentacao oficial

Guias de estilo e melhores praticas

Recursos de aprendizado

Cheat sheets

← Voltar para a lista