Estágio 01 · 01-10
LockedUnix CLI é a linguagem natural de servidores. Toda infra (Docker, K8s, CI/CD, servidores em produção, debugging em incident) acontece em terminal. Devs que dominam shell trabalham 5-10x mais rápido em tarefas de operação.
Sem domínio de shell:
grep quando grep -rn 'pattern' . resolve em 1s.Este módulo te dá fluência em CLI Unix, não receitas, mas modelo mental das ferramentas e composição.
Hierarquia única começando em /:
/
├── bin/ # binários essenciais (ls, cat, sh)
├── boot/ # kernel, initramfs
├── dev/ # device files (/dev/null, /dev/sda, /dev/random)
├── etc/ # configurações sistema
├── home/ # diretórios de usuários (/home/alice)
├── lib/ # bibliotecas compartilhadas
├── opt/ # software opcional
├── proc/ # filesystem virtual com info de processos
├── sys/ # filesystem virtual com info de kernel
├── tmp/ # arquivos temporários (limpo no boot ou via cron)
├── usr/ # programas de usuário (não-essenciais ao boot)
│ ├── bin/
│ ├── lib/
│ └── local/ # programas instalados manualmente
├── var/ # dados variáveis (logs, caches, mail)
└── root/ # home do root
Tudo é arquivo. Devices (/dev/sda), processos (/proc/<pid>/), sockets, FIFOs, links, diretórios, tudo é representado como entrada de FS.
Inode: estrutura de metadados que identifica um arquivo. Contém: tamanho, permissões, owner, timestamps, ponteiros pros blocos de dados. Nome do arquivo NÃO está no inode, está numa entrada de diretório que mapeia nome → inode.
Hard link: outra entrada de diretório apontando pro mesmo inode. ln file link.
Symbolic link (soft link): arquivo especial cujo conteúdo é um path. ln -s file link. Quebra se file move.
ls -i mostra inode. ls -l mostra detalhes.
Cada inode tem:
rwxrwxrwx (owner / group / others)Notação:
rwxr-xr-x755 (rwx=7, r-x=5, r-x=5)chmod:
chmod 755 filechmod u+x file (add execute pro owner)chmod -R go-w dir/ (recursivo, remove write de group/others)chown:
chown user:group filesetuid (s no execute do owner): programa roda com UID do owner. Ex: /usr/bin/passwd é setuid root pra editar /etc/shadow.
sticky bit (t no execute de others): em diretório (ex: /tmp), só owner pode deletar arquivos.
umask: máscara default que subtrai permissões em criação. umask 022 faz arquivos novos serem 644, dirs 755.
Cada processo tem 3 FDs default:
Redirecionamento:
cmd > file, stdout pra file (sobrescreve)cmd >> file, stdout pra file (append)cmd 2> err.log, stderrcmd > out.log 2>&1, stdout e stderr pra mesmo file (2>&1 = "duplica fd 2 pra fd 1")cmd < input, stdin de filecmd <<EOF ... EOF, heredoc (string multilinha como stdin)Pipe:
cmd1 | cmd2, stdout do 1 vira stdin do 2.cat file | grep pattern | sort | uniq -c | sort -rn | headNavegação:
pwd (print working dir)cd <path> (change)ls -la (listar)tree (árvore, pode precisar instalar)Arquivos:
cp src dst (copy)mv src dst (move/rename)rm file (remove). rm -rf dir/ (recursivo, force).mkdir -p path/with/parentstouch file (cria vazio ou atualiza timestamp)cat file (concatenate, mostra)less file (paginate)head -n 20 file, tail -n 20 file, tail -f log (follow)wc -l file (count lines)du -sh dir/ (disk usage)df -h (disk free)Texto:
grep -rn 'pattern' ., busca recursiva, com line numbersgrep -E '...', extended regexgrep -v 'pattern', invert matchsed 's/foo/bar/g' file, substitutesed -i 's/foo/bar/g' file, in placeawk '{print $2}' file, column extraction (campo 2)awk '$3 > 100 {print $1}' file, condicionalcut -d, -f2,4 file.csv, campos delimitadosort file, sort -n (numeric), sort -k2,2uniq -c (count consecutive)tr 'A-Z' 'a-z' (translate)xargs, converte stdin em args (use com find ... | xargs cmd)Procura:
find . -name '*.ts' -type f, busca por nome.find . -mtime -7, modificado nos últimos 7 dias.find . -size +1M, maior que 1 MB.find . -name '*.tmp' -deletelocate file (precisa updatedb).Processos:
ps aux (todos processos)ps -ef, pgrep, pidoftop, htopkill <pid> (envia SIGTERM), kill -9 <pid> (SIGKILL)pkill -f 'pattern' (kill por nome)nohup cmd & (detach + ignore SIGHUP)Rede:
curl -v https://..., HTTP request (use -X POST, -H 'Header', -d 'data').wget url, download.dig example.com, DNS query.ping host, mtr host, traceroute host.ss -tlnp (sockets TCP listening, com PID, moderno; substitui netstat).nc -lvp 1234 (netcat: listener TCP).Compressão:
tar czf out.tar.gz dir/, create + gzip.tar xzf in.tar.gz, extract.gzip file, gunzip file.gz.zstd file (mais moderno).Permissões/users:
whoami, id (UID, GID, groups).sudo cmd, roda como root.su - user, switch.Shebang: #!/usr/bin/env bash no topo. Torna executável: chmod +x script.sh.
Variáveis:
NAME=alice # sem espaços!
echo "$NAME"
echo "${NAME}_suffix"
Quoting:
'literal', sem expansão."with $var", expande variáveis.$(cmd), substitui com saída de comando.`cmd`, legacy, prefira $(...).Condicionais:
if [ "$x" -eq 0 ]; then
echo "zero"
elif [ -f "$f" ]; then
echo "file exists"
else
echo "else"
fi
[ ... ] é o teste. [[ ... ]] é versão Bash mais segura (suporta == com glob, &&, ||).
Operadores comuns:
-eq, -ne, -lt, -le, -gt, -ge=, !=, -z (vazio), -n (não vazio)-e (existe), -f (regular), -d (dir), -r/-w/-x (perms), -s (não vazio)Loops:
for f in *.txt; do
echo "$f"
done
for i in {1..10}; do echo "$i"; done
while read -r line; do
echo "$line"
done < file
Funções:
greet() {
local name="$1" # local!
echo "Hi, $name"
}
greet "Alice"
Argumentos do script:
$0, nome do script$1, $2, ..., args posicionais$@, todos args (lista)$#, quantidade de args$?, exit status do último comando (0 = success)$$, PID do shellSet strict mode (recomendado):
set -euo pipefail
# -e: exit on error
# -u: error on unset variable
# -o pipefail: fail if any command in pipe fails (não só o último)
IFS=$'\n\t' # field separator: newline + tab (não space)
Logs/erros:
log() { echo "[$(date +'%Y-%m-%dT%H:%M:%S')] $*" >&2; }
fail() { log "FATAL: $*"; exit 1; }
env lista todas. printenv VAR. export VAR=value torna disponível pra subprocessos.
PATH é onde shell procura executáveis. ~/.bashrc ou ~/.zshrc configuram.
HOME, USER, SHELL, PWD, OLDPWD, LANG, TZ, EDITOR são clássicas.
$PATH:/new/path adiciona.
ssh user@host, login remoto.
Chaves:
ssh-keygen -t ed25519, gerar (use ed25519, não RSA).~/.ssh/id_ed25519 (private), .pub (public).ssh-copy-id user@host, copia pública pro ~/.ssh/authorized_keys no host.Config (~/.ssh/config):
Host myserver
HostName 192.168.1.10
User alice
Port 2222
IdentityFile ~/.ssh/myserver_key
Aí: ssh myserver.
Port forwarding:
ssh -L 8080:localhost:80 user@host, local 8080 → host:80 (acessar serviço remoto via local).ssh -R 9000:localhost:3000 user@host, reverso.scp e rsync pra transferir.
rsync -av --delete src/ user@host:dst/, sincroniza (incremental, robusto). Padrão pra deploy/backup.
tmux ou screen: multiplexador de terminal, sessão persiste após desconectar SSH.
Cron roda jobs em horários. crontab -e edita.
# m h dom mon dow command
0 3 * * * /opt/backup.sh # 3am todo dia
*/15 * * * * /opt/sync.sh # cada 15 min
0 0 * * 0 /opt/weekly.sh # domingo 00:00
systemd timers é alternativa moderna.
at: schedule único (ex: at now + 1 hour).
/var/log/ contém logs do sistema. journalctl (systemd) é a interface moderna:
journalctl -u nginx, logs do unit nginx.journalctl -f, follow.journalctl --since '1 hour ago'.journalctl -p err, errors./var/log/syslog, /var/log/auth.log (auth events), /var/log/dmesg (kernel).
Ctrl+C envia SIGINT.
Ctrl+Z envia SIGTSTP (pause).
bg (continua em background), fg (volta foreground), jobs (lista).
disown remove do controle do shell (sobrevive a logout).
nohup cmd & similar (ignora SIGHUP).
trap 'echo "got SIGINT"' INT, captura signal em script.
Pra passar o Portão Conceitual, sem consultar:
ls -l mostra link count.755 → letras e vice-versa.passwd).[ ... ], [[ ... ]] e (( ... )) em Bash.set -euo pipefail linha por linha.awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10cmd >file 2>&1 vs cmd 2>&1 >file (ordem importa! segundo redireciona stderr pra terminal).cron e systemd timer.tmux/screen em uma frase.Implementar lograt, analizador de logs estruturados em Bash + (opcional) Node.
lograt é uma CLI que analisa logs de uma aplicação web (formato JSON Lines, um por request) e gera relatórios.
Cada linha é JSON:
{"ts":"2026-04-28T10:23:45Z","method":"GET","path":"/api/users","status":200,"latency_ms":42,"ip":"1.2.3.4","user_id":"u123"}
lograt summary <logfile>, Imprime:
lograt errors <logfile>, só requests 5xx, com timestamp + path + IP.lograt slow <logfile> --threshold 1000, requests > threshold ms.lograt user <user_id> <logfile>, requests de um user específico, ordenadas por timestamp.lograt rate <logfile> --window 60, RPS por janela de 60 segundos.awk, sort, uniq, jq permitido, jq é a única dep externa).- → lê de stdin, pode pipe tail -f log | lograt summary -).awk | sort | uniq que você usa, com explicação linha-a-linha.awk é mais rápido que Python pra processar logs (less overhead, streaming nativo).$ lograt summary access.log
Total: 1,234,567
By status: 2xx=1,100,234 / 3xx=50,000 / 4xx=80,000 / 5xx=4,333
Latency (ms): avg=87, p50=42, p95=320, p99=1,234
Top paths:
423,456 /api/users
234,567 /api/orders
...
gitignore, find, xargs pra operações em massa em repos.awk/jq é a porta de entrada antes de Loki/Grafana.ripgrep (rg): substitui grep, muito mais rápido.fd: substitui find, sintaxe melhor.bat: substitui cat com syntax highlight.exa/eza: substitui ls com cores.fzf: fuzzy finder interativo (use em CLI, em vim, em shell history).tldr: examples curtos por comando (tldr tar).man: manual oficial (man 7 signal).shellcheck: lint pra Bash.Encerramento: após 01-10 você é fluente em terminal, operação, debug, automação. Isso te transforma na sessão de prod a 3am, em CI/CD pipelines, em qualquer ambiente Linux. Pratique diariamente.
Destrava
01-10 é prereq dos seguintes módulos: