Intermediário Fundamental Progresso 0%

Shell

Variáveis, pipes, redirecionamentos e globbing, a linha de comando como ferramenta de poder.

01. Conceito

bash, zsh e sh: qual usar e por quê

Explicação

O shell é o intérprete que lê seus comandos, faz expansões (variáveis, globs, etc.) e pede ao kernel que execute os programas. Existem vários shells — cada um com suas características.

bash (Bourne Again Shell) — o padrão na maioria das distros Linux. Compatível com scripts sh. Configurado em ~/.bashrc (shells interativos não-login) e ~/.bash_profile (shells de login). Se você não sabe qual usar, use bash.

zsh — mais features que bash: autocompletion inteligente, correção automática de typos, themes via Oh My Zsh, melhor histórico compartilhado entre sessões. Padrão no macOS desde Catalina. Configurado em ~/.zshrc.

sh (POSIX shell) — o mínimo compatível com o padrão POSIX. Use o shebang #!/bin/sh em scripts que precisam rodar em qualquer sistema Unix (incluindo sistemas sem bash instalado).

fish (Friendly Interactive Shell) — muito amigável para uso interativo: syntax highlighting em tempo real, sugestões de autocompletion. Porém não é POSIX-compatível — scripts fish não rodam em bash.

Exemplo Concreto
# Ver qual shell você está usando
$ echo $SHELL
/bin/bash

$ echo $0
bash

# Ver shells instalados no sistema
$ cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/zsh
/usr/bin/zsh
/usr/bin/fish

# Mudar shell padrão permanentemente
$ chsh -s /usr/bin/zsh
# (precisa fazer logout/login para ter efeito)

# Diferença de shebang:
#!/bin/bash   # script usa features bash-específicas
#!/bin/sh     # script usa apenas POSIX — mais portável
#!/usr/bin/env bash  # forma mais portável de referenciar bash
O que você precisa guardar
  • bash: padrão no Linux — aprenda bem antes de migrar
  • zsh: mais features interativas; padrão no macOS
  • sh: scripts portáveis — use quando precisar rodar em qualquer Unix
  • fish: ótimo interativo, mas não-POSIX — evite para scripts
  • chsh -s /caminho/shell muda o shell padrão do usuário
02. Ambiente

Variáveis de ambiente: $PATH, $HOME, $USER

Explicação

Variáveis de ambiente são pares chave=valor que o shell mantém e passa para processos filhos. Elas configuram o comportamento do sistema e dos programas.

$PATH — lista de diretórios separados por : onde o shell busca executáveis. Quando você digita python3, o shell percorre $PATH da esquerda para a direita procurando um executável com esse nome. Se não encontrar: command not found.

$HOME — diretório home do usuário atual. Igual a ~.

$USER — nome do usuário atual.

$SHELL — caminho do shell padrão do usuário.

$PWD — diretório atual (equivalente ao output de pwd).

$EDITOR — editor preferido. Usado por git commit, crontab -e, etc.

Para criar uma variável: VARIAVEL=valor (sem export — só no processo atual, processos filhos não veem). Com export VARIAVEL=valor, fica disponível para processos filhos. Para persistir entre sessões, adicione em ~/.bashrc ou ~/.bash_profile.

Exemplo Concreto
# Ver o $PATH atual
$ echo $PATH
/home/usuario/.local/bin:/usr/local/bin:/usr/bin:/bin

# O shell tenta cada diretório em ordem:
# 1. /home/usuario/.local/bin/python3 ?  NÃO
# 2. /usr/local/bin/python3 ?            NÃO
# 3. /usr/bin/python3 ?                  SIM → executa

# Adicionar diretório ao PATH (persistir em ~/.bashrc)
export PATH="$HOME/.local/bin:$PATH"

# Definir editor padrão
export EDITOR=vim

# Variável local vs exportada
TESTE="local"
export TESTE_EXPORT="global"
bash -c 'echo $TESTE'         # vazio — filho não vê
bash -c 'echo $TESTE_EXPORT'  # global — filho vê

# Ver todas as variáveis de ambiente
$ env | sort | head -10
$ printenv HOME

# Carregar arquivo .env de um projeto
$ source .env
$ . .env      # equivalente (. é alias para source)
Erros comuns

Espaços em torno do =VARIAVEL = valor dá erro. Em shell, não pode ter espaço: VARIAVEL=valor sem espaços.

Não usar aspas em valores com espaçosNOME=João Silva vai tentar executar "Silva" como comando. Correto: NOME="João Silva".

Modificar PATH sem o $PATH originalexport PATH=/novo/dir apaga todo o PATH existente. Sempre faça: export PATH="/novo/dir:$PATH".

O que você precisa guardar
  • $PATH determina onde o shell busca executáveis (da esquerda para direita)
  • export VAR=valor — disponível para processos filhos
  • VAR=valor sem export — só no shell atual
  • Persistir variáveis: adicionar em ~/.bashrc (bash) ou ~/.zshrc (zsh)
  • source arquivo carrega variáveis no shell atual (diferente de executar)
03. Fluxo

Pipes e Redirecionamentos

Analogia: Linha de montagem

O pipe é como uma linha de montagem industrial: cada programa faz uma coisa específica e passa o resultado para o próximo. ps aux | grep nginx | awk '{print $2}': ps lista todos os processos, grep filtra só os de nginx, awk extrai só os PIDs. Três ferramentas simples, cada uma com uma função — combinadas em algo poderoso.

Explicação

Pipe | — conecta o stdout de um processo ao stdin do próximo. Os dois processos rodam em paralelo — não é sequencial. O kernel usa um buffer interno para transferir os dados.

> — redireciona stdout para arquivo (sobrescreve o conteúdo existente).

>> — redireciona stdout para arquivo (append — adiciona ao final).

2> — redireciona stderr (file descriptor 2) para arquivo.

2>&1 — redireciona stderr para onde stdout está apontando. A ordem importa — deve vir depois do redirecionamento de stdout.

&> ou >& — redireciona stdout E stderr juntos (bash).

< arquivo — usa arquivo como stdin do programa.

<< EOF — heredoc: stdin multilinha inline no script.

/dev/null — dispositivo que descarta qualquer dado escrito nele. Use para silenciar output indesejado.

Exemplo Concreto
# Pipe — encontrar os 5 processos que mais usam memória
$ ps aux --sort=-%mem | head -6

# Redirecionamento de stdout
$ ls /etc > lista_etc.txt         # sobrescreve
$ ls /etc >> lista_etc.txt        # append

# Redirecionamento de stderr
$ ls /naoexiste 2> erros.txt      # erros vão para arquivo
$ ls /etc /naoexiste &> tudo.txt  # stdout e stderr juntos

# Silenciar completamente
$ comando_barulhento > /dev/null 2>&1

# stdin de arquivo
$ sort < nomes.txt
$ wc -l < arquivo.txt

# Heredoc — útil em scripts
$ cat << EOF
Linha 1
Linha 2
EOF

# Pipeline clássico: contar arquivos por extensão
$ find . -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn
     42 py
     17 txt
      8 sh
      3 json

# Tee — escreve em arquivo E mostra no terminal
$ comando | tee output.txt
$ comando | tee -a output.txt  # append
Erros comuns

Ordem errada em 2>&1comando 2>&1 > arquivo está errado. O stderr vai para o terminal (stdout original), não para o arquivo. Correto: comando > arquivo 2>&1 — primeiro redireciona stdout para arquivo, depois stderr para onde stdout está.

Sobrescrever arquivo com >ls > arquivo.txt em um arquivo existente apaga tudo. Se quiser preservar, use >> ou habilite set -o noclobber no bash.

O que você precisa guardar
  • | conecta stdout → stdin (paralelamente)
  • > sobrescreve; >> adiciona ao final
  • 2>arquivo redireciona stderr; 2>&1 junta com stdout
  • /dev/null descarta qualquer dado — "buraco negro" do Unix
  • Ordem importa: > arq 2>&1 (correto) vs 2>&1 > arq (errado)
04. Descritores

stdin, stdout e stderr: os três file descriptors

Explicação

Todo processo no Unix começa com três file descriptors (FDs) abertos — canais de comunicação numerados:

  • FD 0 — stdin (standard input): entrada padrão. Por default, o teclado. O que o programa "lê" quando você não especifica entrada.
  • FD 1 — stdout (standard output): saída padrão. Por default, o terminal. Onde os resultados são escritos.
  • FD 2 — stderr (standard error): saída de erro. Por default, também o terminal. Onde mensagens de erro são escritas.

Programas bem escritos enviam resultados para stdout e erros para stderr. Isso é fundamental: permite que você processe resultados em um pipeline enquanto ainda vê os erros no terminal, ou que redirecione erros para um arquivo de log separado.

Todos os FDs são, internamente, ponteiros para arquivos — porque no Unix, tudo é arquivo. Você pode redirecionar qualquer FD para qualquer arquivo, dispositivo, socket ou pipe.

Exemplo Concreto
# Ver FDs abertos do seu shell
$ ls -la /proc/$$/fd/
lrwxrwxrwx 0 -> /dev/pts/0    # FD 0 = stdin (terminal)
lrwxrwxrwx 1 -> /dev/pts/0    # FD 1 = stdout (terminal)
lrwxrwxrwx 2 -> /dev/pts/0    # FD 2 = stderr (terminal)

# Separar stdout e stderr de um comando
$ ls /etc /naoexiste > resultados.txt 2> erros.txt
$ cat resultados.txt   # arquivos de /etc
$ cat erros.txt        # "ls: cannot access '/naoexiste'"

# Redirecionar stderr para stdout (útil para grep em erros)
$ make 2>&1 | grep "error:"

# Mandar mensagem de erro explicitamente para stderr em script
$ echo "ERRO: arquivo não encontrado" >&2

# Script bem comportado:
#!/bin/bash
if [ ! -f "$1" ]; then
    echo "Erro: arquivo '$1' não existe" >&2   # erro -> stderr
    exit 1
fi
cat "$1"  # resultado -> stdout (FD 1)
O que você precisa guardar
  • FD 0 = stdin, FD 1 = stdout, FD 2 = stderr
  • Programas bem escritos: resultados → stdout, erros → stderr
  • echo "erro" >&2 — escreve em stderr de dentro de scripts
  • Separar: > ok.log 2> erros.log
  • Juntar: > tudo.log 2>&1 ou &> tudo.log
05. Padrões

Expansão e globbing

Explicação

O shell faz várias expansões antes de executar um comando — transforma o que você digitou em algo concreto. Entender a ordem das expansões evita surpresas.

Globbing (expansão de pathname) — corresponde a nomes de arquivos usando caracteres especiais:

  • * — qualquer sequência de caracteres (exceto /)
  • ? — exatamente um caractere qualquer
  • [abc] — qualquer um dos caracteres listados
  • [a-z] — qualquer caractere no range
  • ** — recursivo (requer shopt -s globstar no bash)

Brace expansion {a,b,c} — o shell gera strings antes de qualquer outra expansão. Não precisa de arquivos existentes. mkdir {jan,fev,mar}_2025 cria três diretórios.

Expansão de variável $VAR — substitui o nome da variável pelo seu valor.

Expansão aritmética $((expr)) — calcula expressões matemáticas.

Substituição de comando $(comando) — executa comando e substitui pelo output.

Exemplo Concreto
# Globbing básico
$ ls *.py             # todos os .py
$ ls arquivo?.txt     # arquivo1.txt, arquivo2.txt, etc.
$ ls [Rr]eadme*       # README ou readme, qualquer extensão

# Brace expansion — não precisa de arquivos existentes
$ mkdir {jan,fev,mar,abr,mai,jun}_2025
$ touch log_{error,warn,info}.txt
$ cp arquivo.txt{,.bak}   # cria arquivo.txt.bak (expansão esperta!)

# Globbing recursivo (requer globstar no bash)
$ shopt -s globstar
$ ls **/*.py          # todos .py em todos os subdiretórios

# Substituição de comando
$ echo "Hoje é $(date +%Y-%m-%d)"
Hoje é 2026-05-20

$ files=$(ls *.log)
$ echo "Encontrei: $files"

# Expansão aritmética
$ echo $((2 ** 10))
1024
$ echo $(($(cat /proc/sys/kernel/pid_max) / 2))

# Aspas: double quotes preservam $VAR; single quotes literal
$ echo "$HOME"     # /home/usuario
$ echo '$HOME'     # $HOME (literal)
Erros comuns

Glob sem aspas em variável — se $ARQUIVO contém espaços ou caracteres glob, usar sem aspas pode causar word splitting e expansão indesejada. Sempre use aspas duplas: "$ARQUIVO".

Brace expansion vs glob{*.py,*.js} não funciona como esperado. Brace expansion acontece antes do glob. Para múltiplas extensões, use: *.py *.js separados por espaço, ou extglob.

O que você precisa guardar
  • * qualquer string; ? um char; [abc] um dos chars
  • {a,b,c} brace expansion — gera strings, não depende de arquivos
  • $(comando) substituição de comando — captura output
  • $((expr)) aritmética no shell
  • Aspas duplas preservam variáveis; aspas simples são completamente literais
06. Produtividade

Histórico e aliases

Explicação

O bash salva os comandos que você digita em ~/.bash_history (zsh usa ~/.zsh_history). O histórico é uma das ferramentas de produtividade mais subestimadas do shell.

Navegação no histórico:

  • / — navega pelo histórico
  • Ctrl+R — busca reversa interativa — comece a digitar e encontra o comando mais recente que combina
  • history — lista o histórico com números
  • !42 — re-executa o comando número 42
  • !! — re-executa o último comando (útil com sudo: sudo !!)
  • !ls — re-executa o último comando que começou com ls

Aliases — atalhos para comandos longos. alias nome='comando longo'. Definidos no shell atual; para persistir, adicione em ~/.bashrc ou ~/.zshrc.

Exemplo Concreto
# Histórico
$ history | tail -10
  421  ls -la /etc/nginx/
  422  sudo nginx -t
  423  sudo systemctl reload nginx
  424  tail -f /var/log/nginx/error.log

$ !422          # re-executa: sudo nginx -t
$ !!            # re-executa último comando
$ sudo !!       # esqueceu o sudo? re-executa com sudo

# Ctrl+R (busca reversa)
# Digite: Ctrl+R → "nginx" → mostra último comando com "nginx"
# Enter para executar, Ctrl+R de novo para buscar anterior
# Ctrl+C para cancelar

# Aliases úteis
$ alias ll='ls -la --color=auto'
$ alias gs='git status'
$ alias gp='git push'
$ alias cls='clear'
$ alias ..='cd ..'
$ alias ...='cd ../..'
$ alias grep='grep --color=auto'

# Ver aliases definidos
$ alias
alias ll='ls -la --color=auto'
alias gs='git status'

# Remover alias
$ unalias gs

# Adicionar em ~/.bashrc para persistir:
# echo "alias ll='ls -la --color=auto'" >> ~/.bashrc
# source ~/.bashrc  # recarregar
ℹ️ Saiba mais

Para aliases mais complexos que precisam de argumentos, use funções no bash:

# Alias não aceita argumentos facilmente — use função
mkcd() {
    mkdir -p "$1" && cd "$1"
}
# mkcd novo_projeto → cria e já entra no diretório
O que você precisa guardar
  • Ctrl+R — busca no histórico (mais útil que ↑↑↑)
  • !! re-executa último; !N re-executa número N; !string re-executa último que começa com string
  • alias nome='comando' — atalhos de comandos
  • Persistir aliases: adicionar em ~/.bashrc e recarregar com source ~/.bashrc
  • Para aliases com argumentos, use funções bash
07. Prática

Terminal Simulado — Pratique aqui

ℹ️ Terminal simulado para prática básica — use um terminal real para comandos avançados.

usuario@linuxwiki: ~
ℹ️ Comandos disponíveis no simulador

Tente: ls, ls -la, pwd, cd documentos, cat notas.txt, echo $HOME, whoami, date, uname -a, history, clear

Use ↑ / ↓ para navegar no histórico de comandos.

🃏 Flashcards

📝 Quiz: Módulo 05