Gestione dei processi

PID e kill

Ogni programma che viene lanciato in una sessione al terminale viene identificato dal kernel come un processo, con la sua allocazione di risorse (come accesso al disco, memoria RAM, cicli di CPU, ecc.).

In particolare, ogni processo viene identificato con un numero intero, detto PID (Process ID). È possibile vedere una lista di tutti i processi attivi sul sistema tramite il comando ps -e ;

Si identifichi, all'interno della lista dei processi, il server che offre il servizio SSH, che si chiama sshd. Suggerimento: non è necessario scorrere manualmente la lista per trovarlo, ma si può usare (ad esempio) il comando grep visto la scorsa volta.

Nel caso si voglia terminare un programma, si può usare il comando kill, oppure killall. Il primo prende come argomento il numero di un processo, il secondo un nome (oppure anche un utente, usando il flag -u). Il secondo comando può essere più semplice da usare per evitare di dover chiamare ps solo per trovare il PID del processo desiderato.

Si provi ad utilizzare il comando kill per terminare il processo sshd, il cui PID è stato determinato nell'esercizio precedente.
Se il comando precedente restituisce un errore, si è in grado di determinarne la ragione?

Il comando kill permette di spedire diversi segnali ai processi. Quello di default è chiamato SIGTERM e chiede "gentilmente" ad un processo di uscire. Al processo si permette di svolgere delle operazioni prima di farlo (come ad esempio di salvare i file aperti). Tuttavia, questo permette anche al processo anche di ignorare la richiesta.

Altri segnali non vengono invece comunicati al processo, ma vengono eseguiti direttamente. Un esempio è il segnale SIGKILL, che uccide un processo "senza ammettere risposta".

Si può scegliere un tipo diverso di segnale con l'opzione (ad esempio) kill -SIGKILL, o anche direttamente con il codice intero che identifica il segnale, come kill -9. Si veda il manuale di kill per ulteriori dettagli.

Si identifichi il PID del processo che gestisce il vostro terminale; come forse ricorderete, la shell che state usando si chiama bash, che è anche il nome del processo. Si utilizzi per kill per ucciderlo, e terminare in modo immediato la propria sessione. Si provi sia con kill senza opzioni, sia con kill -SIGKILL.

Una curiosità: i processi vengono gestiti in modo gerarchico: al boot del sistema viene avviato un processo speciale, detto init, con PID settato a 1. Questo avvierà poi vari processi, come ad esempio l'interfaccia grafica, che a loro volta avvieranno processi, e così via. È possibile visualizzare questa struttura gerarchica di processi tramite il comando pstree.

Return code

Quando un processo termina, ritorna un interno che può essere usato per determinare se il programma ha raggiunto il suo scopo oppure no, e se ha incontrato un errore. L'interpretazione di questo intero è strettamente legata al software, ed ognuno ha le sue convenioni. Tuttavia, normalmente si considera l'intero 0 come "successo", e altri numeri interi come codici di un errore.

Per controllare il codice di errore dell'ultimo programma che è terminato, si può stampare il valore della variabile speciale $?; vedremo poi il significato del simbolo $ nel dettaglio. Il valore della variabile può essere stampato con echo.

Si legga il manuale di grep per capire come interpretare il codice ritornato da grep. Si generino due esempi, uno in cui il codice ritornato sia zero, ed uno in cui invece sia diverso da zero.

Mettere in pausa un processo

Fra i segnali menzionati in precedenza, c'è una coppia che permette di mettere in pausa e riprendere l'esecuzione di un programma. Questi sono i segnali SIGSTOP e SIGCONT.

Si provi ad aprire un secondo terminale, collegandosi sempre alla stessa macchina del laboratorio. Una volta sperimentato questo comportamento, si utilizzi sul primo terminale la combinazione di tasti CTRL+Z per spedire un segnale SIGSTOP al processo corrente. È poi possibile farlo continuare con il comando fg, oppure continuare in background con il comando bg.

Variabili d'ambiente

Come in ogni linguaggio di programmazione, anche in bash è possibile definire delle variabili. Alcune di queste sono già definite con dei valori di default quando effettuiamo il login, e vengono "eredidate" dai processi che lanciamo dal terminale.

In bash le variabili si riconoscono perché preduto da simbolo del dollaro. Ad esempio, $HOME è una delle variabili già definite al momento del login. Ogni apparizione della variabile in un comando viene sostituito con il suo valore, a meno di poche eccezioni, come mostrato dal seguente esempio.

Si provi a stampare il valore della variabile $HOME con il seguente comando:
$ echo $HOME
Cosa succede se si racchiude la variabile $HOME fra virgolette singole o doppie? Potete ipotizzare quale sia la differenze fra questi due tipi di apici?

Possiamo definire altre variabili nella sessione corrente con la sintassi:

$ MIAVARIABILE="prova"
L'uso delle virgolette non è obbligatorio, ma è consigliabile per evitare problemi con la presenza di spazi. Tuttavia, una variabile così definita non verrebbe passata ad un sottoprocesso.
Si provi a definire una nuova variabile, come mostrato sopra, e poi a lanciare una nuova sessione di bash con il comando bash. Provare a stampare il valore della variabile. Cosa succede? Si provi ad uscire dalla sessione annidata, esportare la variabile con il comando export MIAVARIABILE, e ripetere l'esperimento. Il comportamento è cambiato?
Per vedere la lista completa di tutte le variabili pre-definite, ed esportate ai programmi, dette variabili d'ambiente, è possibile utilizzare il comando env.