Marvin Pascale

[B.Log]

24 Settembre 2026

ps

ps aux Ci sono comandi Linux che utilizziamo talmente spesso da finire per considerarli quasi banali.

ps è uno di questi.

Quando qualcosa consuma troppa CPU, quando un demone non vuole saperne di morire o quando vogliamo capire se un servizio è effettivamente partito, la sequenza è più o meno sempre la stessa:

ps aux

oppure:

ps -ef

Magari seguita dal classico:

ps aux | grep nginx

Funziona, naturalmente. Ma fermarsi qui significa utilizzare solo una piccola parte di quello che ps può fare.

ps può diventare uno strumento estremamente preciso per capire cosa sta succedendo all interno di un sistema Linux: gerarchie tra processi, consumo di memoria, thread, stati del kernel, priorità, processi zombie e processi bloccati in I/O.

Vediamo quindi di sporcarci un po le mani.

Una fotografia dei processi

La prima cosa da chiarire è la differenza tra ps e strumenti come top o htop.

top osserva continuamente il sistema e aggiorna periodicamente le informazioni.

ps invece produce una fotografia dello stato dei processi nel momento esatto in cui viene eseguito.

Questa caratteristica lo rende particolarmente interessante negli script e durante il troubleshooting, perché possiamo decidere con precisione quali informazioni visualizzare, filtrarle e ordinarle.

Se lanciamo semplicemente:

ps

otteniamo qualcosa del genere:

PID TTY          TIME CMD
421 pts/0    00:00:00 bash
812 pts/0    00:00:00 ps

Non stiamo vedendo tutti i processi del sistema.

Stiamo vedendo essenzialmente i processi associati al nostro terminale.

Il PID è il Process ID, TTY identifica il terminale, TIME rappresenta il tempo CPU accumulato e CMD indica il comando.

Per una vera analisi del sistema serve qualcosa in più.

ps aux oppure ps -ef?

Le due forme più conosciute sono:

ps aux

e:

ps -ef

Sembrano due modi diversi per fare la stessa cosa e, grossomodo, lo sono: entrambi mostrano i processi del sistema.

La differenza interessante è che ps supporta storicamente diversi stili di opzioni.

Lo stile UNIX utilizza il trattino:

ps -ef

Lo stile BSD permette opzioni senza trattino:

ps aux

Esistono poi le opzioni GNU lunghe:

ps --forest

Questa convivenza di sintassi è uno dei motivi per cui ps può sembrare un comando un po strano.

Ed è anche il motivo per cui:

ps aux

e:

ps -aux

non andrebbero considerati equivalenti.

In generale preferisco scegliere una sintassi e utilizzarla consapevolmente invece di mescolare opzioni BSD e UNIX senza sapere esattamente come verranno interpretate.

Capire davvero ps aux

Un output tipico contiene colonne simili a queste:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1  22528 14336 ?        Ss   08:10   0:02 /sbin/init
www-data  1321  2.1  1.3 420000 98700 ?        Sl   08:20   1:14 nginx

Alcuni valori sono immediati.

USER identifica il proprietario del processo.

PID è il suo identificativo.

%CPU e %MEM indicano rispettivamente utilizzo CPU e memoria.

Ma due colonne meritano particolare attenzione: VSZ e RSS.

VSZ non significa RAM realmente utilizzata

VSZ rappresenta la dimensione dello spazio di memoria virtuale del processo.

Può includere memoria effettivamente utilizzata, librerie mappate, file mappati in memoria e regioni allocate ma non necessariamente residenti in RAM.

Per questo motivo vedere un VSZ enorme non significa automaticamente avere un processo che sta divorando memoria fisica.

RSS, Resident Set Size, indica invece quanta memoria del processo è attualmente residente nella RAM.

Quando sto cercando un processo che occupa realmente memoria, RSS è generalmente un dato molto più interessante.

Per esempio:

ps -eo pid,user,rss,vsz,comm --sort=-rss

ci permette di partire immediatamente dai processi con il maggiore resident set.

STAT: quella colonna che ignoriamo troppo spesso

STAT descrive lo stato del processo.

Alcuni valori fondamentali sono:

R: processo in esecuzione o pronto per essere eseguito.

S: sleep interrompibile. Il processo sta aspettando un evento.

D: sleep non interrompibile, molto spesso collegato a I/O.

T: processo fermato.

Z: zombie.

Esistono inoltre modificatori aggiuntivi.

s indica un session leader.

l indica un processo multithread.

  • indica l appartenenza al foreground process group.

< indica priorità elevata.

N indica una priorità ridotta attraverso nice.

Tra tutti questi, ce ne sono due che durante il troubleshooting meritano immediatamente attenzione: D e Z.

Quando compare D

Un processo nello stato D si trova in uninterruptible sleep.

Tipicamente sta aspettando che il kernel completi una qualche operazione di I/O.

Disco lento, filesystem remoto non raggiungibile, storage problematico o device bloccato sono scenari in cui questo stato può diventare particolarmente interessante.

Possiamo cercarli così:

ps -eo pid,ppid,stat,wchan,cmd | awk "$3 ~ /D/"

La colonna wchan aggiunge un dettaglio prezioso: mostra, quando disponibile, la funzione del kernel sulla quale il processo sta dormendo.

È un piccolo particolare che può trasformare il generico processo bloccato in un indizio molto più concreto.

E soprattutto bisogna ricordare una cosa: un processo nello stato D non sta semplicemente ignorando kill.

Finché rimane bloccato in una determinata attesa non interrompibile, perfino SIGKILL può non produrre un effetto immediato.

In questi casi continuare a lanciare kill -9 non risolve la causa.

Bisogna capire cosa sta aspettando il processo.

Zombie: il colpevole non è quello che sembra

Lo stato Z indica invece un processo zombie.

Il nome può trarre in inganno.

Uno zombie non è un processo ancora attivo che dobbiamo uccidere.

Il processo è già terminato.

Quello che rimane è una piccola struttura mantenuta dal kernel perché il processo padre non ha ancora recuperato il suo exit status.

Per trovarli:

ps -eo pid,ppid,stat,cmd | awk "$3 ~ /Z/"

Qui il dato davvero interessante è PPID.

Se abbiamo:

PID    PPID STAT CMD
7412   2301 Z    [worker] <defunct>

il processo da investigare è soprattutto il 2301.

Lo zombie è il sintomo.

Il padre che non esegue correttamente il reap dei figli è il problema da comprendere.

Basta colonne inutili

Una delle funzioni di ps che trovo più utili è la possibilità di costruire completamente il formato dell output.

Per esempio:

ps -eo pid,ppid,user,%cpu,%mem,stat,etime,cmd

Abbiamo:

PID, identificativo del processo.

PPID, identificativo del padre.

USER, proprietario.

%CPU e %MEM, utilizzo delle risorse.

STAT, stato.

ETIME, tempo trascorso dalla partenza.

CMD, comando.

È molto più leggibile di un output gigantesco quando sappiamo già cosa stiamo cercando.

Altri campi molto interessanti sono:

pgid
sid
uid
gid
rss
vsz
nice
pri
wchan
lstart
comm
args

In particolare comm e args non sono esattamente la stessa cosa.

comm identifica il nome del comando, mentre args permette di vedere la command line completa.

Una distinzione importante quando lo stesso eseguibile viene avviato con configurazioni o parametri differenti.

Ordinare invece di cercare a occhio

Altro errore classico: lanciare ps aux e scorrere centinaia di righe.

Molto meglio lasciare che ps ordini i risultati.

Per CPU:

ps aux --sort=-%cpu

Per memoria:

ps aux --sort=-%mem

Per RSS:

ps aux --sort=-rss# Mani in pasta: ps, molto più di ps aux

Ci sono comandi Linux che utilizziamo talmente spesso da finire per considerarli quasi banali.

ps è uno di questi.

Quando qualcosa consuma troppa CPU, quando un demone non vuole saperne di morire o quando vogliamo capire se un servizio è effettivamente partito, la sequenza è più o meno sempre la stessa:

ps aux


oppure:

ps -ef


Magari seguita dal classico:

ps aux | grep nginx


Funziona, naturalmente. Ma fermarsi qui significa utilizzare solo una piccola parte di quello che ps può fare.

ps può diventare uno strumento estremamente preciso per capire cosa sta succedendo all interno di un sistema Linux: gerarchie tra processi, consumo di memoria, thread, stati del kernel, priorità, processi zombie e processi bloccati in I/O.

Vediamo quindi di sporcarci un po le mani.

## Una fotografia dei processi

La prima cosa da chiarire è la differenza tra ps e strumenti come top o htop.

top osserva continuamente il sistema e aggiorna periodicamente le informazioni.

ps invece produce una fotografia dello stato dei processi nel momento esatto in cui viene eseguito.

Questa caratteristica lo rende particolarmente interessante negli script e durante il troubleshooting, perché possiamo decidere con precisione quali informazioni visualizzare, filtrarle e ordinarle.

Se lanciamo semplicemente:

ps


otteniamo qualcosa del genere:

PID TTY TIME CMD 421 pts/0 00:00:00 bash 812 pts/0 00:00:00 ps


Non stiamo vedendo tutti i processi del sistema.

Stiamo vedendo essenzialmente i processi associati al nostro terminale.

Il PID è il Process ID, TTY identifica il terminale, TIME rappresenta il tempo CPU accumulato e CMD indica il comando.

Per una vera analisi del sistema serve qualcosa in più.

## ps aux oppure ps -ef?

Le due forme più conosciute sono:

ps aux


e:

ps -ef


Sembrano due modi diversi per fare la stessa cosa e, grossomodo, lo sono: entrambi mostrano i processi del sistema.

La differenza interessante è che ps supporta storicamente diversi stili di opzioni.

Lo stile UNIX utilizza il trattino:

ps -ef


Lo stile BSD permette opzioni senza trattino:

ps aux


Esistono poi le opzioni GNU lunghe:

ps –forest


Questa convivenza di sintassi è uno dei motivi per cui ps può sembrare un comando un po strano.

Ed è anche il motivo per cui:

ps aux


e:

ps -aux


non andrebbero considerati equivalenti.

In generale preferisco scegliere una sintassi e utilizzarla consapevolmente invece di mescolare opzioni BSD e UNIX senza sapere esattamente come verranno interpretate.

## Capire davvero ps aux

Un output tipico contiene colonne simili a queste:

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 22528 14336 ? Ss 08:10 0:02 /sbin/init www-data 1321 2.1 1.3 420000 98700 ? Sl 08:20 1:14 nginx


Alcuni valori sono immediati.

USER identifica il proprietario del processo.

PID è il suo identificativo.

%CPU e %MEM indicano rispettivamente utilizzo CPU e memoria.

Ma due colonne meritano particolare attenzione: VSZ e RSS.

### VSZ non significa RAM realmente utilizzata

VSZ rappresenta la dimensione dello spazio di memoria virtuale del processo.

Può includere memoria effettivamente utilizzata, librerie mappate, file mappati in memoria e regioni allocate ma non necessariamente residenti in RAM.

Per questo motivo vedere un VSZ enorme non significa automaticamente avere un processo che sta divorando memoria fisica.

RSS, Resident Set Size, indica invece quanta memoria del processo è attualmente residente nella RAM.

Quando sto cercando un processo che occupa realmente memoria, RSS è generalmente un dato molto più interessante.

Per esempio:

ps -eo pid,user,rss,vsz,comm –sort=-rss


ci permette di partire immediatamente dai processi con il maggiore resident set.

## STAT: quella colonna che ignoriamo troppo spesso

STAT descrive lo stato del processo.

Alcuni valori fondamentali sono:

R: processo in esecuzione o pronto per essere eseguito.

S: sleep interrompibile. Il processo sta aspettando un evento.

D: sleep non interrompibile, molto spesso collegato a I/O.

T: processo fermato.

Z: zombie.

Esistono inoltre modificatori aggiuntivi.

s indica un session leader.

l indica un processo multithread.

* indica l appartenenza al foreground process group.

< indica priorità elevata.

N indica una priorità ridotta attraverso nice.

Tra tutti questi, ce ne sono due che durante il troubleshooting meritano immediatamente attenzione: D e Z.

## Quando compare D

Un processo nello stato D si trova in uninterruptible sleep.

Tipicamente sta aspettando che il kernel completi una qualche operazione di I/O.

Disco lento, filesystem remoto non raggiungibile, storage problematico o device bloccato sono scenari in cui questo stato può diventare particolarmente interessante.

Possiamo cercarli così:

ps -eo pid,ppid,stat,wchan,cmd | awk “$3 ~ /D/”


La colonna wchan aggiunge un dettaglio prezioso: mostra, quando disponibile, la funzione del kernel sulla quale il processo sta dormendo.

È un piccolo particolare che può trasformare il generico processo bloccato in un indizio molto più concreto.

E soprattutto bisogna ricordare una cosa: un processo nello stato D non sta semplicemente ignorando kill.

Finché rimane bloccato in una determinata attesa non interrompibile, perfino SIGKILL può non produrre un effetto immediato.

In questi casi continuare a lanciare kill -9 non risolve la causa.

Bisogna capire cosa sta aspettando il processo.

## Zombie: il colpevole non è quello che sembra

Lo stato Z indica invece un processo zombie.

Il nome può trarre in inganno.

Uno zombie non è un processo ancora attivo che dobbiamo uccidere.

Il processo è già terminato.

Quello che rimane è una piccola struttura mantenuta dal kernel perché il processo padre non ha ancora recuperato il suo exit status.

Per trovarli:

ps -eo pid,ppid,stat,cmd | awk “$3 ~ /Z/”


Qui il dato davvero interessante è PPID.

Se abbiamo:

PID PPID STAT CMD 7412 2301 Z [worker]


il processo da investigare è soprattutto il 2301.

Lo zombie è il sintomo.

Il padre che non esegue correttamente il reap dei figli è il problema da comprendere.

## Basta colonne inutili

Una delle funzioni di ps che trovo più utili è la possibilità di costruire completamente il formato dell output.

Per esempio:

ps -eo pid,ppid,user,%cpu,%mem,stat,etime,cmd


Abbiamo:

PID, identificativo del processo.

PPID, identificativo del padre.

USER, proprietario.

%CPU e %MEM, utilizzo delle risorse.

STAT, stato.

ETIME, tempo trascorso dalla partenza.

CMD, comando.

È molto più leggibile di un output gigantesco quando sappiamo già cosa stiamo cercando.

Altri campi molto interessanti sono:

pgid sid uid gid rss vsz nice pri wchan lstart comm args


In particolare comm e args non sono esattamente la stessa cosa.

comm identifica il nome del comando, mentre args permette di vedere la command line completa.

Una distinzione importante quando lo stesso eseguibile viene avviato con configurazioni o parametri differenti.

## Ordinare invece di cercare a occhio

Altro errore classico: lanciare ps aux e scorrere centinaia di righe.

Molto meglio lasciare che ps ordini i risultati.

Per CPU:

ps aux –sort=-%cpu


Per memoria:

ps aux –sort=-%mem


Per RSS:

ps aux –sort=-rss


Possiamo anche costruirci una vista molto più compatta:

ps -eo pid,user,%cpu,%mem,rss,stat,comm –sort=-rss | head


Oppure per CPU:

ps -eo pid,user,%cpu,%mem,time,comm –sort=-%cpu | head


Il segno meno indica ordinamento decrescente.

Quindi i processi più interessanti finiscono immediatamente in alto.

## Filtrare senza grep

Il famoso:

ps aux | grep nginx


continuerà probabilmente a seguirci per tutta la vita.

Ma ps possiede già strumenti di selezione.

Per PID:

ps -p 1234


Per più PID:

ps -p 1234,5678


Per utente:

ps -u www-data


Per nome del comando:

ps -C nginx


E possiamo naturalmente combinarli con il formato personalizzato:

ps -C nginx -o pid,ppid,user,stat,%cpu,%mem,etime,args


In questo modo otteniamo soltanto ciò che ci interessa e senza il processo grep che compare tra i risultati.

## Chi ha generato chi?

Su Linux quasi ogni processo ha una storia.

Un processo nasce da un altro processo e seguire questa gerarchia è spesso il modo più veloce per capire perché qualcosa esiste.

Possiamo visualizzarla con:

ps -ef –forest


oppure:

ps aux –forest


Un risultato semplificato potrebbe apparire così:

root 1 systemd root 932 sshd marvin 1841 sshd marvin 1842 bash marvin 2110 python worker.py


In pochi secondi abbiamo ricostruito la catena.

systemd ha gestito sshd, sshd ha aperto la sessione, la sessione ha creato la shell e dalla shell è stato avviato Python.

Possiamo anche chiedere direttamente il parent PID:

ps -o ppid= -p 2110


oppure trovare i figli di un determinato processo:

ps –ppid 1842


È particolarmente utile con web server, worker, job scheduler e servizi che generano molti subprocess.

## E i thread?

Linux rappresenta i thread in modo abbastanza particolare e il normale output di ps può nascondere completamente quello che accade all interno di un processo multithread.

Per vedere tutti i thread:

ps -eLf


Per vedere soltanto quelli di un processo:

ps -T -p 1234


Questa vista diventa interessante quando abbiamo un applicazione che apparentemente utilizza moltissima CPU.

A livello di processo vediamo magari un unico PID al 300 per cento su una macchina multicore.

La vista dei thread permette di capire se il lavoro è distribuito oppure se uno specifico thread sta monopolizzando una CPU.

## Una piccola cassetta degli attrezzi

Alla fine, invece di ricordare cento opzioni, bastano poche combinazioni.

Per una panoramica generale:

ps -ef


Per la gerarchia:

ps -ef –forest


Per trovare chi consuma RAM:

ps -eo pid,user,rss,%mem,stat,comm –sort=-rss | head


Per trovare chi consuma CPU:

ps -eo pid,user,%cpu,%mem,stat,comm –sort=-%cpu | head


Per processi in stato D:

ps -eo pid,ppid,stat,wchan,cmd | awk “$3 ~ /D/”


Per gli zombie:

ps -eo pid,ppid,stat,cmd | awk “$3 ~ /Z/”


Per i thread di un processo:

ps -T -p PID


Per ricostruire il padre:

ps -o ppid= -p PID


Sono comandi semplici, ma insieme permettono già di affrontare una buona parte dei problemi quotidiani su un server Linux.

## Conclusioni

ps appartiene a quella categoria di utility UNIX che sembrano semplicissime finché non iniziamo realmente a studiarle.

Possiamo usarlo come una semplice lista dei processi.

Oppure possiamo trasformarlo in uno strumento diagnostico molto preciso.

La differenza sta soprattutto nel capire cosa rappresentano realmente PID, PPID, RSS, VSZ e STAT, nel costruire output mirati con -o e nell usare filtri e ordinamenti invece di setacciare manualmente centinaia di righe.

Quando un server inizia a comportarsi male, spesso non serve partire immediatamente con strumenti complessi.

Una fotografia fatta bene può già raccontare parecchio.

E molto spesso quella fotografia inizia semplicemente con ps.

Possiamo anche costruirci una vista molto più compatta:

ps -eo pid,user,%cpu,%mem,rss,stat,comm --sort=-rss | head

Oppure per CPU:

ps -eo pid,user,%cpu,%mem,time,comm --sort=-%cpu | head

Il segno meno indica ordinamento decrescente.

Quindi i processi più interessanti finiscono immediatamente in alto.

Filtrare senza grep

Il famoso:

ps aux | grep nginx

continuerà probabilmente a seguirci per tutta la vita.

Ma ps possiede già strumenti di selezione.

Per PID:

ps -p 1234

Per più PID:

ps -p 1234,5678

Per utente:

ps -u www-data

Per nome del comando:

ps -C nginx

E possiamo naturalmente combinarli con il formato personalizzato:

ps -C nginx -o pid,ppid,user,stat,%cpu,%mem,etime,args

In questo modo otteniamo soltanto ciò che ci interessa e senza il processo grep che compare tra i risultati.

Chi ha generato chi?

Su Linux quasi ogni processo ha una storia.

Un processo nasce da un altro processo e seguire questa gerarchia è spesso il modo più veloce per capire perché qualcosa esiste.

Possiamo visualizzarla con:

ps -ef --forest

oppure:

ps aux --forest

Un risultato semplificato potrebbe apparire così:

root        1     systemd
root      932       sshd
marvin   1841         sshd
marvin   1842           bash
marvin   2110             python worker.py

In pochi secondi abbiamo ricostruito la catena.

systemd ha gestito sshd, sshd ha aperto la sessione, la sessione ha creato la shell e dalla shell è stato avviato Python.

Possiamo anche chiedere direttamente il parent PID:

ps -o ppid= -p 2110

oppure trovare i figli di un determinato processo:

ps --ppid 1842

È particolarmente utile con web server, worker, job scheduler e servizi che generano molti subprocess.

E i thread?

Linux rappresenta i thread in modo abbastanza particolare e il normale output di ps può nascondere completamente quello che accade all interno di un processo multithread.

Per vedere tutti i thread:

ps -eLf

Per vedere soltanto quelli di un processo:

ps -T -p 1234

Questa vista diventa interessante quando abbiamo un applicazione che apparentemente utilizza moltissima CPU.

A livello di processo vediamo magari un unico PID al 300 per cento su una macchina multicore.

La vista dei thread permette di capire se il lavoro è distribuito oppure se uno specifico thread sta monopolizzando una CPU.

Una piccola cassetta degli attrezzi

Alla fine, invece di ricordare cento opzioni, bastano poche combinazioni.

Per una panoramica generale:

ps -ef

Per la gerarchia:

ps -ef --forest

Per trovare chi consuma RAM:

ps -eo pid,user,rss,%mem,stat,comm --sort=-rss | head

Per trovare chi consuma CPU:

ps -eo pid,user,%cpu,%mem,stat,comm --sort=-%cpu | head

Per processi in stato D:

ps -eo pid,ppid,stat,wchan,cmd | awk "$3 ~ /D/"

Per gli zombie:

ps -eo pid,ppid,stat,cmd | awk "$3 ~ /Z/"

Per i thread di un processo:

ps -T -p PID

Per ricostruire il padre:

ps -o ppid= -p PID

Sono comandi semplici, ma insieme permettono già di affrontare una buona parte dei problemi quotidiani su un server Linux.

Conclusioni

ps appartiene a quella categoria di utility UNIX che sembrano semplicissime finché non iniziamo realmente a studiarle.

Possiamo usarlo come una semplice lista dei processi.

Oppure possiamo trasformarlo in uno strumento diagnostico molto preciso.

La differenza sta soprattutto nel capire cosa rappresentano realmente PID, PPID, RSS, VSZ e STAT, nel costruire output mirati con -o e nell usare filtri e ordinamenti invece di setacciare manualmente centinaia di righe.

Quando un server inizia a comportarsi male, spesso non serve partire immediatamente con strumenti complessi.

Una fotografia fatta bene può già raccontare parecchio.

E molto spesso quella fotografia inizia semplicemente con ps.


Le opinioni in quanto tali sono opinabili e nulla ti vieta di approfondire l’argomento.

Risorse: