Gerenciamento de processos: ps, top, kill, jobs, bg, fg
1. Introdução ao gerenciamento de processos no Bash
No contexto do shell, um processo é qualquer programa em execução no sistema. Cada comando que você digita no terminal gera um ou mais processos. O Bash oferece ferramentas poderosas para monitorar, controlar e gerenciar esses processos.
Processos podem rodar em foreground (primeiro plano) — bloqueando o terminal até sua conclusão — ou em background (segundo plano), permitindo que você continue usando o shell enquanto eles executam.
Cada processo possui um PID (Process ID) único, um PPID (Parent Process ID) que identifica seu processo pai, e pertence a uma sessão. Essa hierarquia é fundamental para entender como os sinais e o controle de jobs funcionam.
2. ps: Monitorando processos em tempo real
O comando ps (process status) é a ferramenta mais básica e versátil para listar processos.
Sintaxe básica:
# Lista todos os processos do sistema no formato BSD
ps aux
# Lista todos os processos no formato System V
ps -ef
# Filtrando por nome com grep
ps aux | grep "nginx"
Visualizando árvore de processos:
# Mostra hierarquia pai-filho
ps -ejH
# Exemplo de saída parcial:
# PID PGID SID TTY TIME CMD
# 1234 1234 1234 pts/0 00:00:00 bash
# 5678 1234 1234 pts/0 00:00:00 sleep 100
Personalizando a saída com -o:
# Mostra apenas PID, nome, uso de CPU e memória
ps -eo pid,comm,%cpu,%mem --sort=-%cpu
# Formato customizado para monitoramento
ps -eo pid,ppid,user,start,time,cmd --sort=start
3. top e htop: Monitoramento interativo de recursos
O top é o monitor interativo clássico do Linux, atualizando a lista de processos em tempo real.
Navegando pelo top:
# Iniciar o top
top
# Comandos interativos dentro do top:
# P - ordenar por uso de CPU
# M - ordenar por uso de memória
# k - matar um processo (solicita PID e sinal)
# r - renice (alterar prioridade)
# u - filtrar por usuário
Exemplo prático:
# Para matar um processo dentro do top:
# 1. Pressione 'k'
# 2. Digite o PID
# 3. Digite o sinal (15 para SIGTERM, 9 para SIGKILL)
Alternativas modernas:
# htop - versão mais amigável com cores e atalhos
# Instalação: sudo apt install htop (Debian/Ubuntu)
htop
# btop - alternativa ainda mais moderna com gráficos
# Instalação via snap ou repositórios
btop
No htop, você pode navegar com setas, matar processos com F9, e ajustar prioridades com F7/F8.
4. kill e sinais: Encerrando e controlando processos
O comando kill envia sinais para processos. Cada sinal tem um comportamento específico.
Sinais comuns:
SIGTERM (15) - Terminação gentil (padrão)
SIGKILL (9) - Mata imediatamente (não pode ser ignorado)
SIGHUP (1) - Recarregar configuração
SIGSTOP (19) - Pausa o processo
SIGCONT (18) - Continua processo pausado
Uso prático:
# Matar por PID
kill 1234 # Envia SIGTERM
kill -9 1234 # Força morte imediata
kill -SIGKILL 1234 # Forma explícita
# Matar por nome
killall firefox # Mata todos os processos chamados "firefox"
killall -9 nginx
# Matar por padrão (mais flexível)
pkill -f "python script.py" # Mata processos cujo comando contém o padrão
pkill -u usuario # Mata todos os processos de um usuário
# Enviar para grupo de processos
kill -- -PGID # Mata todo o grupo
5. Gerenciamento de jobs no shell: jobs, bg, fg
No shell interativo, jobs são processos que você iniciou a partir do terminal atual. O Bash mantém uma tabela de jobs para gerenciá-los.
Comandos essenciais:
# Listar jobs ativos
jobs -l # Mostra PID também
# Iniciar processo em background
sleep 100 & # O & coloca em background
# Suspender processo em foreground
# Pressione Ctrl+Z enquanto o processo roda
# Colocar job suspenso em background
bg %1 # Continua job 1 em background
# Trazer job para foreground
fg %1 # Traz job 1 para foreground
Exemplo completo:
# 1. Iniciar um processo longo
$ sleep 300
^Z # Ctrl+Z suspende
[1]+ Stopped sleep 300
# 2. Ver jobs
$ jobs -l
[1]+ 5678 Suspended: 18 sleep 300
# 3. Colocar em background
$ bg %1
[1]+ sleep 300 &
# 4. Trazer de volta ao foreground
$ fg %1
sleep 300
6. Controlando processos no terminal: suspensão e resumo
A diferença entre suspender (SIGTSTP) e colocar em background é sutil mas importante:
- Suspender (Ctrl+Z): pausa o processo, mantendo-o na tabela de jobs
- Background (
bgou&): permite que o processo continue executando
Exemplos práticos:
# Rodar compilação longa em background
make -j4 & # Compila usando 4 núcleos em background
# Cuidado: se o terminal fechar, o processo morre
# Soluções:
disown -h %1 # Remove job da tabela, mas mantém rodando
nohup long_script.sh & # Ignora SIGHUP (terminal fechando)
Protegendo processos com nohup:
# Script que continua mesmo após logout
nohup ./meu_script.sh > saida.log 2>&1 &
# Para encontrar depois:
ps aux | grep meu_script
7. Prioridades e nice: ajustando recursos da CPU
O Linux usa um sistema de prioridades (nice values) para alocar CPU. Valores variam de -20 (mais prioritário) a 19 (menos prioritário).
Comandos nice e renice:
# Iniciar processo com prioridade baixa
nice -n 10 ./script_pesado.sh
# Iniciar com prioridade alta (requer root)
sudo nice -n -10 ./urgente.sh
# Alterar prioridade de processo já rodando
renice -n 5 -p 1234 # Reduz prioridade do PID 1234
sudo renice -n -5 -p 5678 # Aumenta prioridade (root)
# Monitorar prioridades
ps -eo pid,comm,nice,pri --sort=nice
Quando usar:
# Evitar travamentos: processos pesados com nice alto
nice -n 15 ffmpeg -i video.mp4 output.avi &
# Priorizar processos do usuário
sudo renice -n -10 -u $USER
8. Boas práticas e automação
Script para matar processos por nome ou idade:
#!/bin/bash
# kill_old_processes.sh - Mata processos antigos por nome
PROCESS_NAME="node"
MAX_AGE_HOURS=24
ps aux | grep "$PROCESS_NAME" | grep -v grep | while read line; do
PID=$(echo $line | awk '{print $2}')
ELAPSED=$(echo $line | awk '{print $10}')
# Converte tempo decorrido para horas (simplificado)
if [[ $ELAPSED == *":"* ]]; then
HOURS=$(echo $ELAPSED | cut -d: -f1)
if [ "$HOURS" -gt "$MAX_AGE_HOURS" ]; then
echo "Matando PID $PID ($PROCESS_NAME) - rodando há $HOURS horas"
kill -15 $PID 2>/dev/null || kill -9 $PID
fi
fi
done
Combinando ps, kill e cron para limpeza automática:
# Cron job que roda a cada hora
# 0 * * * * /usr/local/bin/kill_old_processes.sh
# Script para matar processos zumbis (estado Z)
ps aux | awk '$8=="Z" {print $2}' | xargs -r kill -9 2>/dev/null
Armadilhas comuns:
- Zombies: processos que já morreram mas ainda estão na tabela (não podem ser mortos, o pai precisa coletá-los)
- Orphans: processos cujo pai morreu — são adotados pelo init (PID 1)
- Processos órfãos: podem continuar rodando sem supervisão
Para evitar problemas, sempre use wait em scripts que disparam processos em background:
#!/bin/bash
job1 &
JOB1_PID=$!
job2 &
JOB2_PID=$!
wait $JOB1_PID
wait $JOB2_PID
echo "Ambos os jobs terminaram"
Referências
- GNU Coreutils: ps invocation — Documentação oficial do comando ps com todas as opções disponíveis
- Linux man page: top — Manual completo do top, incluindo todos os comandos interativos e opções de linha de comando
- The Linux Kernel: Signals — Documentação oficial sobre sinais Linux, incluindo SIGTERM, SIGKILL e SIGHUP
- Bash Reference Manual: Job Control — Seção oficial do manual Bash sobre controle de jobs, bg, fg e disown
- Linux man page: nice and renice — Manual completo dos comandos nice e renice para ajuste de prioridades
- htop - an interactive process viewer — Site oficial do htop com documentação, downloads e guia de uso