Tutto quello che devi sapere su ps

Tutto quello che devi sapere su ps

All'interno di un sistema Unix-like (e non solo, visto che anche Windows usa la stessa logica) ogni istanza di programma in esecuzione è contraddistinta da un identificativo, un numero progressivo assegnato dal sistema detto Process ID o più in breve PID. Il PID è quindi il nome univoco di un certo processo e come si crede nel Vudù, sapere il vero nome di qualcosa ti da grande potere su di essa. Nel nostro caso è ad esempio possibile inviare segnali al processo, chiedergli di chiudersi o anche terminarlo di forza con il comando kill, ma anche scoprire su di esso informazioni interessanti quali ad esempio chi è l'utente che lo ha lanciato, da quanto sta girando e cosa sta facendo inquesto momento.

Per ispezionare lo stato dei processi attivi da riga di comando si utilizza il comando ps. Ad esempio se lancio il comando ps in questo momento su un terminale della mia macchina ottengo:

$ ps
  PID TTY          TIME CMD
 4567 pts/0    00:00:00 bash
 8432 pts/0    00:00:00 ps

Ossia la lista dei processi in esecuzione in quel terminale in questo momento. Le quattro colonne della tabella indicano:

  • PID: è il process ID del processo indicato dalla riga
  • TTY: è l'identificativo del terminale a cui quel processo è legato
  • TIME: è la somma del cpu time che il processo ha utilizzato finora
  • CMD: è il nome del programma in esecuzione in quel processo

Quindi nel mio caso abbiamo il processo con PID 4567 che sta eseguendo la shell Bash, quella su cui ho lanciato il comando ps, e poi c'è il processo 8432 che è proprio il comando ps stesso in esecuzione.

Attenzione: questa visualizzazione è quella di default sulle macchine Linux, ma ad esempio su FreeBSD le colonne riportate sono leggermente diverse

Come abbiamo detto di default ps riporta solo i processi relativi al terminale corrente, se vogliamo invece vedere informazioni su tutti i processi dell'utente corrente in qualunque terminale essi si trovino possiamo usare lo switch a:

$ ps a
  PID TTY      STAT   TIME COMMAND
 1298 tty7     Ssl+   5:00 /usr/lib/xorg/Xorg -core :0 -seat seat0 -auth /var/run/lightdm/root/:0 -nolisten tcp vt7 -novtswitch
 4567 pts/0    Ss+    0:00 bash
 9212 pts/2    Ss     0:00 bash
10158 pts/2    R+     0:00 ps a

In questo caso vediamo molti processi in più, infatti in questo momento ho attiva sia l'interfaccia grafica (PID 1298), sia due shell Bash (PID 4567 e 9212). Notiamo inoltre che la visualizzazione è cambiata, infatti adesso si è aggiunta la colonna STAT e la colonna COMMAND ha sostituito CMD. Ciò avviene perché ho usato lo switch a che come avrete notato non è preceduto dal -. Vediamo perché.

Famiglie di switch

Il comando ps, un po' come tutti i comandi Unix, si è evoluto negli anni in modo diverso su varie piattaforme, sviluppando varianti negli switch. Ad esempio su Linux ps presenta 3 diverse famiglie di switch:

  • UNIX: switch che sono preceduti dal simbolo -, ad esempio ps -A
  • BSD: switch che non vengono preceduti da dal simbolo -, ad esempio ps a
  • GNU: switch preceduti da --, ad esempio ps --user www-data Mentre su FreeBSD la famiglia di switch GNU non è stata implementata.

Ogni switch ha le sue caratteristiche specifiche e occorre studiarsi un po' la man page di ps per avere piena consapevolezza di quale switch usare in ogni situazione.

Ad esempio:

  • ps a visualizza tutti i processi lanciati del sistema che siano collegati ad un terminale in formato BSD
  • ps x visualizza tutti i processi lanciati dall'utente corrente indipendentemente dal fatto che siano o meno collegati ad un terminale in formato BSD
  • ps ax visualizza tutti i processi del sistema che siano collegati ad un terminale o meno in formato BSD
  • ps -A visualizza la lista di tutti i processi nel sistema in formato UNIX
  • ps -AF visualizza la lista di tutti i processi nel sistema in formato esteso
  • ps -a visualizza tutti i processi del sistema che siano associati ad un terminale e che non siano "di testa"
  • ps -x visualizza visualizza tutti i processi lanciati dall'utente corrente indipendentemente dal fatto che siano o meno collegati ad un terminale (come ps x)

Si noti che ps x e ps -x sono praticamente equivalenti ma la stessa cosa NON vale per ps a e ps -a dove il secondo visualizza tutti i processi del sistema ma escludendo quelli non associati a terminali e i processi "di testa", come ad esempio le shell che lanciano altri comandi.

Uno dei problemi nell'uso quotidiano di ps è che le opzioni BSD e quelle UNIX si possono si usare insieme, ma talvolta la loro combinazione produce risultati inaspettati. Ad esempio cosa accade se lancio ps a -A? Le due opzioni richiedono a ps due comportamenti diversi e non conciliabili e in questo caso a viene ignorato a favore di -A. In altri casi invece il comportamento del comando può variare in funzione dell'ordine in cui inserisco gli switch. Riassumendo il mio consiglio è di evitare il più possibile di mischiare i due diversi stili di switch, e farlo solo quando siete sicuri di quello che state facendo.

Chi ha lanciato questo processo?

Come abbiamo visto è possibile ottenere una lista dei processi, ma come possiamo sapere quale utente ha lanciato un certo processo? Facile usando lo switch u. Ad esempio:

$ ps uax
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1 225584  9100 ?        Ss   10:23   0:02 /sbin/init splash
root         2  0.0  0.0      0     0 ?        S    10:23   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        I<   10:23   0:00 [rcu_gp]
root         4  0.0  0.0      0     0 ?        I<   10:23   0:00 [rcu_par_gp]
...

elenca tutti i processi in esecuzione nel sistema e chi li ha lanciati. Notiamo che di nuovo i dati riportati dal comando sono diversi infatti il flag u attiva la visualizzazione di alcune colonne informative aggiuntive come la percentuale di CPU e memoria attualmente utilizzate dal processo stesso, ma anche la data e ora di avvio del processo nella colonna START.

L'output di ps aux può essere veramente lungo, e se stiamo cercando i programmi eseguiti da un utente in particolare può essere utile utilizzare lo switch -u:

ps -u www-data
  PID TTY          TIME CMD
 1296 ?        00:00:00 php-fpm7.2
 1297 ?        00:00:00 php-fpm7.2
 1376 ?        00:00:00 apache2
 1377 ?        00:00:00 apache2
 1378 ?        00:00:00 apache2
 1379 ?        00:00:00 apache2
 1380 ?        00:00:00 apache2
 5794 ?        00:00:00 apache2
 5811 ?        00:00:00 apache2
 5812 ?        00:00:00 apache2
 5813 ?        00:00:00 apache2

In questo esempio ho visualizzato tutti i processi in esecuzione dell'utente www-data.

Personalizzare la visualizzazione dei processi

Tramite l'utilizzo dello switch -o è possibile personalizzare l'output del comando ps. Ad esempio se volessi visualizzare la lista dei miei processi attivi comprendendo il PID, il Parent PID (cioè il PID del processo padre) e il comando di lancio per esteso:

$ ps -o pid,ppid,command
  PID  PPID COMMAND
 9212  4560  bash
17122  9212 ps -o pid,ppid,cpu,command

Dall'output si vede bene, tra l'altro, come il processo 9212, una shell Bash, abbia lanciato il processo 17122, cioè il mio comando ps. La lista completa delle colonne visualizzabili la potete trovare digitando man ps, comunque qui ne elenco alcune:

  • cmd : nome del programma eseguito
  • command : stringa di comando completa in esecuzione
  • pcpu : utilizzo della CPU
  • flags : flag di esecuzione
  • pid : PID del processo
  • ppid : PID del processo padre
  • size : memoria utilizzata dal processo (in KBytes)
  • tty : nome del terminale associato al processo (? se non disponibile)
  • start_time : ora di avvio del processo
  • uid : id utente proprietario del processo
  • user : utente proprietario del processo
  • vsize : memoria virtuale utilizzata (in KBytes)
  • priority : priorità nello scheduler (nice)

Visualizzare i rapporti padre-figlio

Se siete interessati a visualizzare in maniera grafica i rapporti padre-figlio dei processi, su Linux c'è la possibilità di visualizzare una sorta di grafo che li rappresenta con l'opzione GNU --forest, ad esempio:

$ ps -A --forest
  PID TTY          TIME CMD
    2 ?        00:00:00 kthreadd
    3 ?        00:00:00  \_ rcu_gp
    4 ?        00:00:00  \_ rcu_par_gp
    6 ?        00:00:01  \_ kworker/0:0H-kb
    9 ?        00:00:00  \_ mm_percpu_wq
   10 ?        00:00:01  \_ ksoftirqd/0
   11 ?        00:00:19  \_ rcu_sched
    ...

Su FreeBSD questa opzione non c'è, ma lo switch -d produce qualcosa di molto simile.

Ordinare l'output di ps

Spesso capitadi vole individuare quali processi utilizzano più cpu, oppure più memoria o swap, in questi casi è molto utile poter ordinare l'output di ps grazie all'opzione --sort:

$ ps aux --sort=size
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    ...
mysql     1322  0.1  2.5 1692040 205632 ?      Sl   10:23   0:26 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid
maurizio  2924  5.6  6.6 3775516 531656 ?      Sl   10:24  21:25 /usr/lib/firefox/firefox

In questo caso vediamo come il processo di Firefox, con il suo utilizzo del 6.6% della memoria (531656 kilobytes su 8GB di memoria fisica disponibile), sia quello che ne occupa di più. L'opzione sort consente anche, inserendo un - davanti al parametro di ordinamento, di specificare se eseguire l'ordinamento decrescente. Esempio:

$ ps aux --sort=-%mem
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
maurizio  2988  2.0  6.5 3472972 528436 ?      Sl   10:24   8:39 /usr/lib/firefox/firefox -contentproc -childID 1 -isForBrowser -prefsLen 1
maurizio  4861  8.6  6.2 3323964 501436 ?      Sl   10:35  35:55 /usr/lib/firefox/firefox -contentproc -childID 8 -isForBrowser -prefsLen 8
maurizio  2871  1.0  6.1 3233524 493992 ?      Sl   10:24   4:33 /usr/lib/thunderbird/thunderbird
    ...

In qesto caso abbiamo elencato i processi attivi ordnati per percentuale di memoria fisica attualmente utilizzata in ordine decrescente, quindi ai primi posti troviamo i processi che stanno usando più memoria.

Anche in questo caso l'opzione --sort non è disponibile in FreeBSD, che invece offre degli switch di ordinamento per occupazione di memoria -m e per utilizzo di cpu -r.

Gli stati dei processi

Il comando ps deve al suo nome proprio alle iniziali delle parole "Process Status" ed è nato per permettere di avere informazioni sullo stato dei processi. Lo stato di un processo è la condizione in cui si trova un processo in un dato istante. Ogni sistema operativo ha una sua diversa interpretazione dei possibili stati di un processo, vediamo qui sotto a titolo di esempio alcuni degli stati più comuni all'interno di un sistema Linux o FreeBSD:

  • R: processo in esecuzione o in coda di esecuzione
  • S: processo in attesa di (es. input utente o attesa altri processi)
  • D: processo è in attesa di dati dal sistema e non può essere interrotto (di solito impegnato in processi di input/output)
  • Z: processo terminato ma non ancora separato dal processo padre (solitamente detto Zombie)
  • T : processo è stato fermato o da un segnale di stop (SIGSTOP) o è stato tracciato (ad esempio attraverso un software di debug)

Eseguendo il comando ps aux tra le varie colonne sarà visualizzata anche STAT che contiene appunto lo stato del processo ed altre informazioni relative allo stato di esecuzione. Il primo carattere della colonna STAT può essere infatti una delle lettere che abbiamo visto sopra, ed indica lo stato di esecuzione del processo. Dopo questo carattere possono esserne presenti altri che aggiungono informazioni sullo stato del processo. Ecco una lista dei più comuni:

  • < : il processo ha una priorità più alta del normale
  • N : il processo ha una priorità più bassa del normale
  • E : il processo sta tentando di uscire (terminare)
  • s : il processo è un "session leader", cioè è il processo che ha inizializzato il terminale
  • + : il processo sta girando in "foreground", cioè se è in un terminale è il processo che attualmente ha il controllo del terminale

Vediamo di nuovo un esempio per chiarire le cose, se dal mio terminale impartisco:

$ ps -o pid,ppid,stat,time,cmd
  PID  PPID STAT     TIME CMD
 4567  4560 Ss   00:00:00 bash
20511  4567 R+   00:00:00 ps -o pid,ppid,stat,time,cmd

vedo che i miei due processi attivi sono la shell bash, che in questo momento è in stato S, infatti sta attendendo che il comando ps che ha lanciato termini la sua esecuzione, ed è "session leader" in quanto è il primo processo lanciato dentro il suo terminale. Invece il secondo processo è il comando ps stesso che è in esecuzione (stato R) e in questo momento è in "foreground" (+).

ps e larghezza del terminale

A volte i comandi che impartiamo sulla command line, sono piuttosto lunghi e non entrano nella visualizzazione del terminale, infatti di default ps tronca ogni riga di output ad un numero di caratteri pari alla larghezza dello schermo. Per evitare questo comportamento si può usare lo switch w per fare in modo che ps consideri la larghezza dello schermo di 132 colonne, oppure ww per fare in modo che ps ignori totalmente la larghezza dello schermo ed eviti di troncare le righe di output. Esempio ps auxww.

Alcuni esempi dalla "vita reale"

Per concludere, vediamo qui alcuni utili esempi di utilizzo di ps nella vita di tutti i giorni. Gli esempi utilizzano la sintassi Linux.

Selezionare i processi che occupano di più la CPU in questo momento:

$ ps -A -o pid,ppid,cmd,%mem,%cpu --sort=-%cpu | head
PID  PPID CMD                         %MEM %CPU
2924  2343 /usr/lib/firefox/firefox     7.1  6.1
2988  2924 /usr/lib/firefox/firefox -c  6.7  2.0
4861  2924 /usr/lib/firefox/firefox -c  6.5  8.6
2871  2343 /usr/lib/thunderbird/thunde  5.7  1.0
14468 14467 telegram-desktop --          5.3  3.2
4691  2924 /usr/lib/firefox/firefox -c  5.1  0.9
4792  2924 /usr/lib/firefox/firefox -c  4.3  1.3
5474  2924 /usr/lib/firefox/firefox -c  3.3  1.0
4746  2924 /usr/lib/firefox/firefox -c  3.2  1.6

Selezionare i processi che occupano più memoria in questo momento:

$ ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head
PID  PPID CMD                         %MEM %CPU
2924  2343 /usr/lib/firefox/firefox     7.2  6.1
4861  2924 /usr/lib/firefox/firefox -c  6.5  8.6
2988  2924 /usr/lib/firefox/firefox -c  6.4  2.0
2871  2343 /usr/lib/thunderbird/thunde  5.7  1.0
14468 14467 telegram-desktop --          5.3  3.2
4691  2924 /usr/lib/firefox/firefox -c  5.1  0.9
4792  2924 /usr/lib/firefox/firefox -c  4.3  1.3
5474  2924 /usr/lib/firefox/firefox -c  3.3  1.0
4746  2924 /usr/lib/firefox/firefox -c  3.2  1.6

Contare i processi attivi di un certo programma:

$ ps -A | grep apache2 | wc -l
9

Currently there are no comments, so be the first!