Salta al contenuto principale

ps e kill: guarda i processi e fermali

Inviato da tuxsa il

ps mostra quali programmi sono in esecuzione sul sistema in questo momento, e kill permette di intervenire su di essi, per esempio fermando uno che non risponde più. Insieme sono lo strumento di base per capire "cosa sta girando" e "come lo chiudo" quando un programma si blocca.

Prima di cominciare: cos'è un processo

Un processo è un programma in esecuzione. Ogni processo ha:

  • un PID (process id), il numero che lo identifica, assegnato dal sistema all'avvio;
  • un PPID, il PID del processo "genitore" che lo ha avviato: i processi formano un albero, e il capostipite è il processo con PID 1 (di solito systemd);
  • un proprietario, cioè l'utente con i cui permessi sta girando.

Anche la shell in cui scrivi i comandi è un processo, e ogni comando che lanci diventa un suo "figlio".

Cos'è

ps è l'abbreviazione di process status, "stato dei processi". Fa parte del pacchetto procps (nella versione procps-ng) ed è un eseguibile (/usr/bin/ps).

kill è invece un nome ingannevole: serve a inviare un segnale a un processo, e "uccidere" è solo il caso più comune. Esiste in due versioni, come comando interno di Bash e come eseguibile (/usr/bin/kill, sempre da procps), con un comportamento praticamente identico.

Cosa fanno

  • ps stampa una fotografia dei processi nell'istante in cui lo lanci: non si aggiorna da solo. Per un elenco che si aggiorna di continuo esistono top e htop.
  • kill invia un segnale al processo di cui indichi il PID. Il segnale di default è SIGTERM, una richiesta cortese di terminare: il programma può salvare i dati, chiudere i file e uscire in modo ordinato.

Come si usano

$ ps [opzioni]
$ kill [-segnale] PID...

Esempio 1: ps senza opzioni

$ ps
    PID TTY          TIME CMD
   2841 pts/0    00:00:00 bash
   3120 pts/0    00:00:00 ps

Senza opzioni mostra solo i processi dell'utente e del terminale correnti: qui la shell (bash) e lo stesso ps. La colonna TIME è il tempo di processore consumato, non il tempo trascorso.

Esempio 2: tutti i processi del sistema con ps aux

$ ps aux | head -n 4
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.1 168940 13120 ?        Ss   06:58   0:03 /sbin/init
root           2  0.0  0.0      0     0 ?        S    06:58   0:00 [kthreadd]
enzo        2841  0.0  0.1  10220  5280 pts/0    Ss   07:02   0:00 -bash

La forma ps aux (senza trattino) mostra tutti i processi di tutti gli utenti. Le colonne principali:

ColonnaSignificato
USERProprietario del processo
PIDIdentificativo del processo
%CPUUso del processore (media sull'intera vita del processo, non il valore istantaneo)
%MEMPercentuale di memoria fisica usata
VSZ / RSSMemoria virtuale / memoria fisica occupata, in kibibyte
TTYTerminale di controllo (? significa nessuno: tipico dei servizi)
STATStato del processo (vedi sotto)
START / TIMEQuando è partito / tempo di processore consumato
COMMANDIl comando con cui è stato avviato; tra parentesi quadre i processi del kernel

Esempio 3: la forma alternativa ps -ef

$ ps -ef | head -n 4
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 06:58 ?        00:00:03 /sbin/init
root           2       0  0 06:58 ?        00:00:00 [kthreadd]
enzo        2841    2830  0 07:02 pts/0    00:00:00 -bash

ps -ef (con il trattino) mostra gli stessi processi ma con la colonna PPID, il genitore. Sono due stili storici (BSD e UNIX) che ps accetta entrambi: ps aux e ps -ef sono le due forme da ricordare.

Esempio 4: lo stato di un processo (colonna STAT)

LetteraStato
RIn esecuzione (running)
SIn attesa di un evento, interrompibile (il caso più comune)
DIn attesa, non interrompibile (di solito operazioni su disco o rete)
TFermato (per esempio con Ctrl+Z)
ZZombie: terminato, ma il genitore non ne ha ancora raccolto l'uscita

Dopo la lettera principale possono comparire dei simboli: s (capo di una sessione), l (più thread), + (in primo piano sul terminale), < e N (priorità alta o bassa).

Esempio 5: cercare un processo per nome

$ ps aux | grep nginx
root      1320  0.0  0.1  ... nginx: master process /usr/sbin/nginx
www-data  1321  0.0  0.1  ... nginx: worker process
enzo      3402  0.0  0.0  ... grep --color=auto nginx

L'ultima riga è lo stesso grep, che compare perché la parola "nginx" è nella sua riga di comando. Per evitarlo ci sono due strade. La prima è il trucco delle parentesi quadre, che fa sì che il testo cercato non corrisponda alla riga di grep:

$ ps aux | grep [n]ginx

La seconda, più semplice, è pgrep, pensato proprio per questo:

$ pgrep nginx
1320
1321
$ pgrep -a nginx          # mostra anche il comando completo
$ pgrep -u mario firefox  # solo i processi dell'utente mario
$ pidof nginx             # tutti i PID su una riga

Esempio 6: scegliere le colonne e ordinare

$ ps -eo pid,user,%mem,%cpu,comm --sort=-%mem | head -n 4
    PID USER     %MEM %CPU COMMAND
   3310 enzo      8.4  2.1 firefox
   1520 mysql     4.2  0.3 mysqld
   1180 www-data  1.9  0.0 php-fpm8.3

Con -eo (tutti i processi, colonne a scelta) indichi tu quali campi mostrare, e con --sort l'ordine: il segno - davanti alla colonna significa "dal più grande". È il modo rapido per scoprire quali processi occupano più memoria (--sort=-%mem) o più processore (--sort=-%cpu).

Esempio 7: l'albero dei processi

$ ps -ef --forest
...
root      1320     1  0 06:58 ?        00:00:00 /usr/sbin/nginx
www-data  1321  1320  0 06:58 ?        00:00:00  \_ nginx: worker process
www-data  1322  1320  0 06:58 ?        00:00:00  \_ nginx: worker process

Con --forest i processi figli sono mostrati sotto il genitore. Esiste anche pstree, che disegna lo stesso albero in forma più compatta.

Esempio 8: un processo preciso

$ ps -p 2841
$ ps -fp 2841             # con più dettagli (compreso il genitore)
$ ps -u enzo              # tutti i processi dell'utente enzo

Esempio 9: fermare un processo con kill

Lanciamo un processo di prova che dorme per cinque minuti, tenuto in secondo piano:

$ sleep 300 &
[1] 4021
$ ps -p 4021
    PID TTY          TIME CMD
   4021 pts/0    00:00:00 sleep
$ kill 4021
[1]+  Terminato               sleep 300

Il numero tra parentesi quadre è il numero di job della shell, il secondo è il PID. Il processo ha ricevuto SIGTERM e si è chiuso. Per i processi lanciati dalla stessa shell si può usare anche il numero di job con il segno di percentuale: kill %1.

Esempio 10: i segnali

Il comando kill -l elenca tutti i segnali disponibili. I più utili:

NumeroNomeEffetto
15SIGTERMRichiesta di terminare: è il segnale di default, il processo può chiudersi in modo ordinato
9SIGKILLTerminazione immediata, eseguita dal kernel: il processo non può né intercettarla né ignorarla
2SIGINTInterruzione: lo stesso segnale di Ctrl+C
1SIGHUP"Riaggancio": molti servizi lo interpretano come "rileggi la configurazione"
19SIGSTOPSospende il processo, senza possibilità di ignorare il segnale
18SIGCONTRiprende un processo sospeso

Il segnale si indica per numero o per nome, con o senza il prefisso SIG; le forme seguenti sono equivalenti:

$ kill -9 4021
$ kill -KILL 4021
$ kill -SIGKILL 4021

Esempio 11: prima con le buone, poi con le cattive

La regola è partire sempre da kill PID (SIGTERM) e usare kill -9 solo se il processo non risponde dopo qualche secondo:

$ kill 4021
$ ps -p 4021                # c'è ancora?
$ kill -9 4021              # ultima risorsa

Con SIGKILL il programma non ha modo di salvare nulla né di ripulire dopo di sé: file temporanei, file di blocco e dati non scritti possono restare in uno stato incoerente.

Esempio 12: sospendere e riprendere un processo

$ kill -STOP 4021           # il processo si ferma
$ kill -CONT 4021           # riprende da dove era

È utile, per esempio, per liberare temporaneamente il processore da un'elaborazione pesante senza perderne il lavoro fatto.

Esempio 13: fermare per nome con pkill e killall

$ pkill firefox             # invia SIGTERM ai processi che corrispondono a "firefox"
$ pkill -u mario            # tutti i processi dell'utente mario
$ pkill -f "backup.py"      # cerca nella riga di comando completa
$ killall firefox           # per nome esatto

Sono comodi, ma possono colpire più processi di quelli che pensi. Prima di usare pkill, controlla con lo stesso criterio cosa verrebbe colpito:

$ pgrep -a -f "backup.py"
$ pkill -f "backup.py"

Con pgrep e pkill i criteri di ricerca sono gli stessi, e pgrep -a mostra a colpo d'occhio chi verrebbe fermato.

Esempio 14: i processi degli altri utenti

Un utente normale può inviare segnali solo ai propri processi. Per gli altri serve sudo:

$ kill 1320
bash: kill: (1320) - Operazione non permessa
$ sudo kill 1320

Esempio 15: uso negli script

Uno script che ferma un programma in modo ordinato e, se non risponde, lo forza:

#!/bin/bash
PID=$(pgrep -o -f "miascript.py")

[ -n "$PID" ] || { echo "Processo non in esecuzione"; exit 1; }

kill "$PID"
sleep 5

if kill -0 "$PID" 2>/dev/null; then
    echo "Non risponde, forzo la chiusura"
    kill -9 "$PID"
else
    echo "Terminato correttamente"
fi

Con pgrep -o si prende il processo più vecchio tra quelli trovati. Il segnale speciale 0 non fa nulla al processo: kill -0 serve solo a verificare se esiste ancora (restituisce successo se sì, errore se no).

Opzioni utili

Per ps:

  • ps aux e ps -ef: tutti i processi del sistema, nei due formati classici.
  • -p PID: un processo preciso; -u utente: i processi di un utente.
  • -eo colonne: sceglie le colonne (pid, ppid, user, %cpu, %mem, etime, comm, cmd...).
  • --sort=-%mem: ordina in base a una colonna; il segno - inverte l'ordine.
  • --forest: mostra l'albero genitore-figlio.
  • -w: non taglia le righe lunghe alla larghezza dello schermo.

Per kill, pkill e pgrep:

  • kill -l: elenca i segnali.
  • kill -SEGNALE PID: invia il segnale indicato (per numero o per nome).
  • pgrep -a modello: elenca i processi con il comando completo; pgrep -f: cerca nell'intera riga di comando.
  • pkill -u utente modello: limita la ricerca ai processi di un utente.

Attenzione a

  • Prima SIGTERM, poi SIGKILL: kill -9 dovrebbe essere l'ultima risorsa, non l'abitudine. Toglie al programma ogni possibilità di chiudersi in modo ordinato.
  • Controlla il PID: con ps -p PID verifica che sia davvero il processo che intendi fermare. Un PID digitato male può colpire un altro programma, magari uno importante.
  • pkill e killall sono ampi: pkill python ferma tutti i programmi Python, non solo il tuo. Anteponi sempre pgrep -a con lo stesso criterio. Su alcuni sistemi Unix commerciali, inoltre, killall ha tutt'altro significato (termina tutti i processi): su Linux non succede, ma conviene saperlo.
  • I processi in stato D (attesa non interrompibile) non reagiscono nemmeno a kill -9 finché l'operazione su disco o rete non si sblocca. Spesso il vero problema è l'unità o la connessione.
  • Gli zombie (Z) sono già terminati: non occupano risorse, se non una riga nella tabella dei processi, e non si possono "uccidere". Se ne accumulano, bisogna fermare o riavviare il processo genitore (colonna PPID).
  • I servizi vanno gestiti dal loro gestore: se un servizio è controllato da systemd, fermalo con sudo systemctl stop nomeservizio. Un semplice kill potrebbe far sì che systemd lo riavvii subito.
  • Il genitore e i figli: terminare un genitore non sempre termina i figli. Guarda l'albero con ps -ef --forest prima di decidere.
  • Segnali verso processi di sistema: kill -9 -1 invia SIGKILL a tutti i tuoi processi, comprese la sessione grafica e il terminale. Non provarlo per curiosità.
  • I numeri di PID vengono riusati: se tieni il PID di un processo per molto tempo (per esempio in un file), controlla che appartenga ancora allo stesso programma prima di inviargli un segnale.
  • %CPU in ps non è istantaneo: è la media dall'avvio del processo. Per vedere cosa sta consumando adesso usa top o htop.

Riepilogo

ComandoCosa fa
psProcessi del terminale corrente
ps auxTutti i processi, con utente, CPU e memoria
ps -efTutti i processi, con il PID del genitore
ps -ef --forestAlbero dei processi
ps aux --sort=-%mem | headI processi che usano più memoria
ps -p PIDUn processo preciso
pgrep -a nomeCerca i processi per nome
kill PIDChiede al processo di terminare (SIGTERM)
kill -9 PIDTermina subito il processo (SIGKILL)
kill -STOP PID / kill -CONT PIDSospende / riprende un processo
kill -lElenca i segnali
pkill nomeInvia un segnale ai processi con quel nome
kill -0 PIDVerifica se il processo esiste ancora