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 BSDps x
visualizza tutti i processi lanciati dall'utente corrente indipendentemente dal fatto che siano o meno collegati ad un terminale in formato BSDps ax
visualizza tutti i processi del sistema che siano collegati ad un terminale o meno in formato BSDps -A
visualizza la lista di tutti i processi nel sistema in formato UNIXps -AF
visualizza la lista di tutti i processi nel sistema in formato estesops -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