Dia 5: Processos e Jobs no Linux — ps, top, kill e Sinais
No Linux, tudo o que corre é um processo — uma instância de um programa em execução, com o seu próprio espaço de memória, identificadores e prioridade. O kernel atribui a cada processo um PID (Process ID) único e gere o seu acesso ao CPU, memória e ficheiros. Saber listar, monitorizar, suspender, retomar e terminar processos é a base de qualquer administração de sistemas: é o que se faz quando um serviço fica sem resposta, quando o CPU está a 100% sem razão aparente, ou quando se precisa de lançar um job longa-duração em segundo plano.
Este artigo cobre os pilares do dia 5: listar processos com ps, monitorizar em tempo real com top e htop, contolar prioridades com nice e renice, jobs e controlo de sessão com jobs, fg, bg e nohup, e terminar processos com kill e sinais Unix. No fim sabe responder a um servidor lento sem o reiniciar — em vez de kill -9 à primeira queixa, sabe identificar o PID culpado, baixar-lhe a prioridade e só então terminá-lo de forma controlada.
Neste artigo
O Que é um Processo? PID, PPID e Estados
Quando se executa um comando no terminal — digamos sleep 60 — o kernel cria um processo. Esse processo recebe um PID (Process IDentifier) único e incremental. O processo que o originou — neste caso a shell — é o seu PPID (Parent PID). Tudo descende de PID 1, que em distribuições modernas é o systemd (noutras era o init System V). Quando o PID 1 morre, o kernel entra em pânico.
Cada processo está, em cada instante, num destes estados (a coluna STAT do ps):
| Estado | Significado | Quando |
|---|---|---|
R (Running) |
Em execução ou na fila de espera para correr | A usar CPU activamente |
S (Sleep) |
Adormecido, à espera de um evento | À espera de I/O, timer ou sinal |
D (Uninterruptible) |
Sleep ininterruptível — não responde a sinais | À espera de I/O de disco (ex.: fsck) |
T (Stopped) |
Parado por um sinal | Depois de Ctrl+Z ou kill -STOP |
Z (Zombie) |
Terminou mas o pai ainda não leu o estado de saída | Bug no processo pai — ver Erros Comuns |
Existem ainda sufixos que se juntam ao estado principal: + significa processo em foreground (a correr no terminal activo), s indica session leader e l indica processo multi-threaded. Assim, Ss+ significa “session leader, sleeping, foreground” — o que é tipicamente a própria shell.
Para ver o PID da própria shell em uso:
echo $$
# Output: 12345 (o PID da shell actual)
# Confirmar que é real
ps -p $$ -o pid,ppid,comm
# PID PPID COMM
# 12345 12330 bash
# O PPID é o terminal ou processo que lançou esta shell
O /proc filesystem — visto no Dia 2 — expõe informação detalhada sobre cada processo em /proc/<PID>/. O ficheiro /proc/<PID>/status contém o estado, UID, memória e muito mais. Todas as ferramentas que vamos ver — ps, top, htop — lêem o /proc por baixo.
Listar Processos com ps
O ps é a ferramenta fundamental para listar processos num dado instante — um snapshot, não tempo real. Aceita opções em três estilos: Unix (com -), BSD (sem -) e GNU longas (com --). A combinação mais útil no dia-a-dia é ps aux (estilo BSD) — lista todos os processos do sistema, com utilizador, PID, CPU, memória e comando completo. A documentação oficial está em ps(1) — man7.org.
# Snapshot de todos os processos (estilo BSD)
ps aux
# Output (primeiras linhas):
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# root 1 0.0 0.1 169372 13248 ? Ss 09:00 0:02 /sbin/init
# root 2 0.0 0.0 0 0 ? S 09:00 0:00 [kthreadd]
# user 1234 0.5 2.3 850340 47000 ? Sl 09:05 0:01 /usr/bin/python3 app.py
# user 1250 0.0 0.3 21456 6200 pts/0 R+ 09:10 0:00 ps aux
Colunas-chave do ps aux:
| Coluna | Significado |
|---|---|
USER |
Utilizador dono do processo |
PID |
Identificador único do processo |
%CPU |
Percentagem de CPU usada desde o arranque do processo |
%MEM |
Percentagem de memória RAM física usada |
VSZ |
Virtual Memory Size (KiB) — memória virtual total alocada |
RSS |
Resident Set Size (KiB) — memória física efectivamente em uso |
STAT |
Estado do processo (ver tabela acima) |
START |
Hora em que o processo arrancou |
TIME |
Tempo total de CPU acumulado (não tempo decorrido) |
COMMAND |
Comando executado (com argumentos) |
Outras variações essenciais:
# Árvore de processos — mostra hierarquia pai/filho
ps axjf
# ou pstree (pacote separado: apt install pstree / dnf install pstree)
# Só os meus processos nesta shell
ps ux
# Informação detalhada de um PID específico
ps -p 1234 -o pid,ppid,user,stat,%cpu,%mem,etime,comm
# Processos de um utilizador específico
ps -u www-data
# Processos ordenados por consumo de memória (top 10)
ps aux --sort=-%mem | head -11
# Processos ordenados por consumo de CPU (top 10)
ps aux --sort=-%cpu | head -11
A opção --forest (ou axjf no estilo BSD) é particularmente útil para entender a hierarquia de processos — por exemplo, confirmar que todos os workers de um serviço descendem do mesmo master. O comando pstree oferece a mesma visão de forma mais visual.
Monitorização em Tempo Real: top e htop
Enquanto o ps dá um snapshot estático, o top mostra os processos em tempo real, actualizados a cada 3 segundos por defeito. É a primeira ferramenta a abrir quando um servidor está lento. Documentação oficial: top(1) — man7.org.
# Abrir o top
top
# Output (resumo do cabeçalho):
# top - 09:30:00 up 3:20, 2 users, load average: 0.45, 0.30, 0.20
# Tasks: 142 total, 1 running, 141 sleeping, 0 stopped, 0 zombie
# %Cpu(s): 5.0 us, 1.2 sy, 0.0 ni, 93.5 id, 0.3 wa, 0.0 hi, 0.0 si
# MiB Mem : 2048.0 total, 512.0 free, 1024.0 used, 512.0 buff/cache
# MiB Swap: 1024.0 total, 1024.0 free, 0.0 used. 800.0 avail Mem
#
# PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
# 1234 user 20 0 850340 47000 8000 S 5.0 2.3 0:01.23 python3
# 1250 user 20 0 21456 6200 3100 R 0.3 0.3 0:00.01 top
O cabeçalho do top é tão importante quanto a lista de processos. Os campos-chave:
| Campo | Interpretação |
|---|---|
load average |
Média de processos na fila de CPU em 1, 5 e 15 minutos. Acima do nº de cores = gargalo |
%Cpu(s) us |
CPU em espaço de utilizador. sy = kernel. id = idle (livre) |
%Cpu(s) wa |
I/O wait — processos à espera de disco. Valor alto = disco lento |
MiB Mem |
Memória total, livre, usada e buff/cache. O buff/cache é recuperável |
MiB Swap |
Swap em uso. Se crescer continuamente, há falta de RAM |
PR / NI |
Prioridade de scheduling (kernel) e valor nice (definido pelo utilizador) |
Atalhos essenciais dentro do top:
# Dentro do top:
P # Ordenar por CPU (defeito)
M # Ordenar por memória
N # Ordenar por PID
T # Ordenar por tempo de CPU
1 # Mostrar CPU por core (expandir)
k # Matar um processo (pede PID e sinal)
r # Renice (pede PID e novo valor nice)
q # Sair
htop é uma alternativa moderna e mais intuitiva ao top: usa cores para indicar tipo de uso de CPU e memória, permite navegar com setas, matar processos com F9 e renice com F7/F8, e mostra a árvore de processos com F5. Não vem instalado por defeito em todas as distribuições — veja htop — Arch Wiki para detalhes.
# Instalar htop
# Debian/Ubuntu:
sudo apt install htop
# Fedora/RHEL/Rocky:
sudo dnf install htop
# Arch:
sudo pacman -S htop
# Executar
htop
Nota: O top está presente em praticamente todas as distribuições Linux — é uma ferramenta POSIX garantida. O htop é opcional. Em servidores minimalistas (containers, imagens cloud) pode não haver htop instalado — é prudente dominar ambos.
Prioridades: nice e renice
O nice value é um número de -20 a 19 que controla a prioridade de scheduling de um processo: -20 é a prioridade mais alta (mais CPU), 19 é a mais baixa. Por defeito, os processos arrancam com nice 0. Só o root pode baixar o nice (valores negativos); um utilizador normal só pode subi-lo (valor positivo). A regra mnemónica é: nice alto = processo “simpático” = cede CPU aos outros. Documentação: nice(1) — man7.org.
# Lançar um comando com nice +10 (baixa prioridade)
nice -n 10 tar czf backup.tar.gz /home/user/
# Lançar com nice -5 (alta prioridade — só root)
sudo nice -n -5 make -j$(nproc)
# Ver o nice actual de um processo
ps -p 1234 -o pid,ni,comm
# PID NI COMM
# 1234 10 tar
# Alterar o nice de um processo já a correr (renice)
renice 5 -p 1234
# Renice de todos os processos de um utilizador
sudo renice 10 -u www-data
Cenário típico: um backup noturno que não deve competir com o serviço em produção. Em vez de o deixar a nice 0, arranca-se com nice -n 19 — só usa CPU quando ninguém mais precisa. Inversamente, um processo crítico de monitorização pode ser renice para -5 para garantir que responde mesmo sob carga.
Atenção: O nice value não é uma percentagem de CPU nem um limite (limit). Define apenas a prioridade relativa. Um processo a nice 19 ainda pode usar 100% de CPU se não houver mais nada a pedir o CPU. Para limitar de facto o consumo, usa-se o systemd-run com CPUQuota=50% ou cgroups — fora do âmbito deste artigo.
Jobs e Controlo de Sessão — bg, fg, nohup
Quando se executa um comando no terminal, ele corre em foreground — a shell fica bloqueada até o comando terminar. Mas é possível enviar o comando para background (continua a correr, a shell fica livre), trazê-lo de volta para foreground, suspender e retomar. Este mecanismo chama-se job control e é uma funcionalidade da shell (bash, zsh).
# Lançar um comando em background directamente (com &)
sleep 300 &
# [1] 13456 — o [1] é o job number, 13456 é o PID
# Continuar a trabalhar na shell...
echo "A shell está livre"
# Ver os jobs activos
jobs
# [1]+ Running sleep 300 &
# Suspender um processo em foreground com Ctrl+Z
# (envia SIGSTOP ao processo)
sleep 60
# ^Z
# [2]+ Stopped sleep 60
# Retomar em background
bg %2
# [2]+ sleep 60 &
# Trazer um job de background para foreground
fg %1
# sleep 300
# Enviar sinal a um job por número
kill %1 # termina o job 1
O problema do job control é que, quando a shell termina — por exemplo, ao fechar o terminal ou uma sessão SSH — todos os jobs recebem SIGHUP (Signal HangUP) e morrem. Para evitar isto, usa-se o nohup (No HangUP) ou disown.
# nohup: ignora SIGHUP, output vai para nohup.out
nohup ./script-longo.sh &
# nohup: ignoring input and appending output to 'nohup.out'
# Combinar nohup + nice para um backup em background
nohup nice -n 10 tar czf /backup/home.tar.gz /home/ &
# Disown: remover um job já a correr do controlo da shell
./script.sh &
disown %1
# Agora o processo sobrevive ao fecho do terminal
# Melhor prática moderna: systemd-run para serviços temporários
systemd-run --user --unit=backup-home \
/usr/bin/tar czf /backup/home.tar.gz /home/
Nota: O nohup e disown resolvem o problema de um processo morrer ao fechar o terminal, mas em servidores modernos a abordagem correcta é usar systemd-run ou criar uma unit de systemd. O systemd gere reinícios, logs e dependências — algo que nohup não faz. Veja systemd — Arch Wiki para aprofundar.
kill e Sinais Unix — TERM, KILL, HUP e Outros
O kill não mata — envia sinais. O nome é enganador. Um sinal é uma notificação assíncrona enviada pelo kernel a um processo: “alguma coisa aconteceu, reage”. O processo pode capturar o sinal, ignorá-lo (alguns) ou usar o comportamento por defeito. Quando se faz Ctrl+C no terminal, a shell envia SIGINT (Signal Interrupt) ao processo em foreground. Documentação: signal(7) — man7.org e kill(1) — man7.org.
Os sinais mais importantes no dia-a-dia:
| Sinal | Número | Acção |
|---|---|---|
SIGTERM |
15 | Pedido de terminação graciosa — defeito do kill. O processo pode capturar e fazer cleanup |
SIGKILL |
9 | Terminação imediata — não pode ser capturado nem ignorado. Último recurso |
SIGINT |
2 | Interrompido pelo utilizador (Ctrl+C) |
SIGHUP |
1 | Hangup — terminal fechado. Muitos daemons usam-no para recarregar config |
SIGSTOP |
19 | Pausa o processo — não pode ser ignorado (equivalente a Ctrl+Z) |
SIGCONT |
18 | Retoma um processo pausado |
SIGUSR1 / SIGUSR2 |
10 / 12 | Sinais definidos pela aplicação — muitos daemons fazem reload ou dump de estado |
# Terminação graciosa (SIGTERM = 15) — DEFEITO
kill 1234
# ou explicitamente:
kill -15 1234
kill -TERM 1234
# Forçar terminação imediata (SIGKILL = 9) — último recurso
kill -9 1234
kill -KILL 1234
# Pedir a um daemon para recarregar configuração (SIGHUP)
kill -HUP $(cat /var/run/nginx.pid)
# Pausar e retomar um processo
kill -STOP 1234
kill -CONT 1234
# Listar todos os sinais disponíveis
kill -l
# 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
# 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
# 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
# ...
A regra de ouro é sempre tentar SIGTERM primeiro. O SIGKILL (-9) não dá ao processo qualquer hipótese de fazer cleanup: ficheiros temporários ficam órfãos, ligações de base de dados podem ficar abertas, buffers não são flushed. Usar kill -9 como primeiro instinto é um erro comum de administradores inexperientes.
Atenção: Um processo no estado D (Uninterruptible Sleep) não morre nem com kill -9. Está bloqueado no kernel à espera de I/O. A única forma de o remover é resolver o problema de I/O subjacente — normalmente um disco que deixou de responder.
pgrep e pkill — Encontrar e Terminar por Nome
Descobrir o PID com ps aux | grep nginx funciona, mas é frágil: o próprio grep aparece nos resultados, e o parsing de ps é sensível a colunas. O pgrep e pkill resolvem isto de forma limpa. Documentação: pgrep(1) — man7.org e pkill(1) — man7.org.
# Encontrar PIDs por nome de processo
pgrep nginx
# 1234
# 1235
# 1236
# Ver nome e PID juntos
pgrep -a nginx
# 1234 nginx: master process /usr/sbin/nginx
# 1235 nginx: worker process
# Procurar por utilizador específico
pgrep -u www-data nginx
# Terminar todos os processos com nome "nginx"
sudo pkill nginx
# Enviar sinal específico
sudo pkill -HUP nginx # reload
sudo pkill -TERM nginx # terminação graciosa (defeito)
sudo pkill -9 nginx # força bruta
# Por utilizador
sudo pkill -u www-data
# Padrão exacto (-x) em vez de substring
pkill -x sleep # só "sleep", não "sleep_helper"
O pkill é conveniente mas perigoso: pkill ssh pode matar a própria sessão SSH em uso. Sempre que possível, usar pgrep -a primeiro para confirmar a lista de PIDs antes de pkill.
Erros Comuns
Erros recorrentes no trabalho com processos, e como os evitar:
1. Usar kill -9 como primeiro instinto
O SIGKILL não permite cleanup. Primeiro kill PID (SIGTERM), esperar 5-10 segundos, e só se o processo persistir usar kill -9 PID. Para serviços geridos pelo systemd, systemctl stop servico é sempre preferível a kill manual.
2. pkill com nome parcial mata processo errado
pkill python mata também python3, python3.11 e qualquer processo com “python” no nome. Usar -x para match exacto, ou confirmar com pgrep -a antes.
3. Processo zombie (Z) que não desaparece
Um processo zombie já terminou mas o pai não leu o seu estado de saída. Não adianta kill -9 no zombie — já está morto. A solução é kill o processo pai (PPID). Para identificar o pai: ps -o ppid= -p <PID_zombie>.
# Encontrar zombies
ps aux | awk '$8 ~ /Z/ {print}'
# Para cada zombie, descobrir o pai
ps -o pid,ppid,comm -p 9999
# PID PPID COMM
# 9999 8888 [defunct]
# Matar o pai (cuidado: pode ser um daemon importante)
sudo kill 8888
4. Fechar terminal e o processo morre
Esquecer o nohup ou disown e o processo recebe SIGHUP ao fechar o SSH. Para tarefas longas, usar nohup ... & ou, melhor ainda, tmux / screen para manter a sessão.
5. Confundir %CPU do ps com tempo real
O %CPU do ps é a média desde o arranque do processo — um processo que começou há 5 minutos a 50% e passou a 0% mostra ~25%. Para CPU instantâneo, usar top ou htop.
Checklist Rápido
Antes de avançar para o próximo dia, confirmar que se consegue fazer o seguinte — cada item tem um link para a secção relevante do artigo:
- Explicar a diferença entre PID e PPID e identificar o estado de um processo na coluna
STATdops(R, S, D, T, Z) - Listar todos os processos do sistema com
ps auxe identificar os 10 que mais consomem memória ou CPU - Abrir o
top, interpretar o load average e o I/O wait, e saber ordenar por memória comM - Instalar e usar o
htop— navegar, ver árvore de processos comF5e matar comF9 - Lançar um processo com
nice -n 10e alterar a prioridade de um processo a correr comrenice - Suspender um processo com
Ctrl+Z, mandar para background combge trazê-lo de volta comfg - Garantir que um processo sobrevive ao fecho do terminal com
nohupoudisown - Terminar um processo com
kill PID(SIGTERM) e só recorrer akill -9se o SIGTERM falhar - Usar
pgrep -apara encontrar processos por nome epkillpara os terminar — validando antes - Resolver um processo zombie matando o pai (PPID), não o próprio zombie
Artigos Relacionados
- Dia 1: Terminal, Shell e Comandos Essenciais — base de navegação e redirecionamento que este artigo assume
- Dia 2: Sistema de Ficheiros Linux — FHS, Mounts e Links — o
/procfilesystem onde o kernel expõe informação de processos - Diagnóstico de Problemas de Arranque em Linux: Causa e Resolução — como o PID 1 (systemd) arranca e gere todos os outros serviços
- Sistemas Operativos no kbase.pt — mais artigos Linux e administração de sistemas