La shell è ``l'intermediario'' tra l'utente e il sistema, e di conseguenza il mezzo normale attraverso cui si può avviare e controllare un processo. Un comando impartito attraverso una shell può generare più di un processo, per esempio quando viene avviato un programma o uno script che avvia a sua volta diversi programmi, oppure quando si realizzano delle pipeline. Per questo motivo, quando si vuole fare riferimento all'attività derivata da un comando dato attraverso una shell, si parla di job e non di singoli processi.
Attraverso alcune shell è possibile gestire i job che in questo caso rappresentano raggruppamenti di processi generati da un unico comando.
La shell bash, e in generale le shell POSIX, oltre a ksh e csh, gestiscono i job. Nelle sezioni seguenti si fa riferimento al comportamento di bash (in qualità di shell POSIX), ma la maggior parte di quanto spiegato in queste sezioni vale anche per ksh e csh.
<!> Non si deve confondere un job di shell con un processo. Un processo è un singolo eseguibile messo in funzione: se questo a sua volta avvia un altro eseguibile, viene generato un nuovo processo a esso associato. Un job di shell rappresenta tutti i processi che vengono generati da un comando impartito tramite la shell stessa. Basta immaginare cosa succede quando si utilizza una canalizzazione di programmi (pipe), dove l'output di un programma è l'input del successivo.
L'attività di un job può avvenire in foreground (in primo piano) o in background (in sottofondo). Nel primo caso, il job impegna la shell e quindi anche il terminale, mentre nel secondo la shell è libera da impegni e così anche il terminale.
Di conseguenza, non ha senso pretendere da un programma che richiede l'interazione continua con l'utente che possa funzionare in background.
Se un programma richiede dati dallo standard input o ha la necessità di emettere dati attraverso lo standard output o lo standard error, per poterlo avviare come job in background, bisogna almeno provvedere a ridirigere l'input e l'output.
Un programma viene avviato esplicitamente come job in background quando alla fine della riga di comando viene aggiunto il simbolo &. Per esempio:
#
make zImage > ~/make.msg &
avvia in background il comando make zImage (per generare un kernel), dirigendo lo standard output verso un file per un possibile controllo successivo dell'esito della compilazione.
Dopo l'avvio di un programma come job in background, la shell restituisce una riga contenente il numero del job e il numero del primo processo generato da questo job (PID). Per esempio:
[1] 173
rappresenta il job numero 1 che inizia con il processo 173.
Se viene avviato un job in background e questo a un certo punto ha la necessità di emettere dati attraverso lo standard output o lo standard error e questi non sono stati ridiretti, si ottiene una segnalazione simile alla seguente.
[1]+ Stopped (tty output) pippo
Nell'esempio, il job avviato con il comando pippo si è bloccato in attesa di poter emettere dell'output.
Nello stesso modo, se viene avviato un job in background e questo ad un certo punto ha la necessità di ricevere dati dallo standard input e questo non è stato ridiretto, si ottiene una segnalazione simile alla seguente.
[1]+ Stopped (tty input) pippo
Se è stato avviato un job in foreground e si desidera sospenderne
l'esecuzione, si può inviare attraverso la tastiera, il carattere susp che di
solito si ottiene con la combinazione
Quando un job viene sospeso, la shell genera una riga come nell'esempio seguente:
[1]+ Stopped pippo
dove il job pippo è stato sospeso.
jobs [<opzioni>] [<job>]
Il comando di shell jobs, permette di conoscere l'elenco dei job esistenti e il loro stato. Per poter utilizzare il comando jobs occorre che non ci siano altri job in esecuzione in foreground, di conseguenza, quello che si ottiene è solo l'elenco dei job in background.
-
l
Permette di conoscere anche il numero PID del processo leader di ogni job.
-
p
Emette solo i numeri PID del processo leader di ogni job.
$
jobs
Si ottiene l'elenco normale dei job in background. Nel caso dell'esempio seguente, il primo job è in esecuzione, il secondo è sospeso in attesa di poter emettere l'output, l'ultimo è sospeso in attesa di poter ricevere l'input.
[1] Running yes >/dev/null &
[2]- Stopped (tty output) mc
[3]+ Stopped (tty input) unix2dos
$
jobs -
l
Si ottiene l'elenco dei job in background con in più l'indicazione del PID del processo leader di ogni job.
[1] 232 Running yes >/dev/null &
[2]- 233 Stopped (tty output) mc
[3]+ 235 Stopped (tty input) unix2dos
L'elenco di job ottenuto attraverso il comando jobs, mostra in
particolare il simbolo + a fianco del numero del job ``attuale'',
ed eventualmente il simbolo -
a fianco di quello che diventerebbe il
job attuale se il primo termina o viene comunque eliminato.
Il job attuale è quello a cui si fa riferimento in modo predefinito tutte le volte che un comando richiede l'indicazione di un job e questo non viene fornito.
Di norma si indica un job con il suo numero preceduto dal simbolo %, ma si possono anche utilizzare altri metodi elencati nella tabella (seguente).
fg [<job>]
Il comando fg porta in foreground un job che prima era in background. Se non viene specificato il job su cui agire, si intende quello attuale.
bg [<job>]
Il comando bg permette di fare riprendere (in background) l'esecuzione di un job sospeso. Ciò è possibile solo se il job in questione non è in attesa di un input o di poter emettere l'output. Se non si specifica il job, si intende quello attuale.
Quando si utilizza la combinazione
kill [
-
s <segnale> | -
<segnale>] [<job>]
Il comando kill funziona quasi nello stesso modo del programma omonimo. Di solito, non ci si rende conto che si utilizza il comando e non il programma. Il comando kill, in particolare rispetto al programma omonimo, permette di inviare un segnale al processo leader di un job, indicando direttamente il job.
Attraverso il comando interno trap è possibile ``intrappolare'' ed eventualmente attribuire un comando (comando interno, funzione, programma o alias) a un segnale particolare.
In questo modo, uno script può gestire i segnali. L'esempio seguente ne mostra uno (trappola) in grado di reagire ai segnali SIGUSR1 e SIGUSR2 emettendo un semplice messaggio.
#!/bin/bash
trap 'echo "Ho intrappolato il segnale SIGUSR1"' SIGUSR1
trap 'echo "Ho intrappolato il segnale SIGUSR2"' SIGUSR2
while [ 0 ] # ripete continuamente
do
NULLA="ciao" # esegue una operazione inutile
done
Supponendo di avere avviato lo script nel modo seguente,
$
trappola &
e che il suo numero PID sia 1234...
$
kill -
s SIGUSR1 1234
Ho intrappolato il segnale SIGUSR1
$
kill -
s SIGUSR2 1234
Ho intrappolato il segnale SIGUSR2
trap [
-
l] [<comando>] [<segnale>]
Il comando espresso come argomento di trap, viene eseguito quando la
shell riceve il/i segnale/i indicati.
Se non viene fornito il comando, o se al suo posto si mette un trattino
(-
), tutti i segnali specificati sono riportati al loro valore originale
(i valori che avevano al momento dell'ingresso nella shell), cioè riprendono il
loro significato normale.
Se il comando fornito corrisponde a una stringa nulla, il segnale relativo viene ignorato
dalla shell e dai comandi che questo avvia.
Il segnale può essere espresso in forma verbale (per nome) o con il suo numero.
Se il segnale è EXIT, pari a zero, il comando viene eseguito all'uscita della
shell.
Se viene utilizzato senza argomenti, trap emette la lista di comandi associati con ciascun numero di segnale.
$
trap '
ls -
l'
SIGUSR1
Se la shell riceve un segnale SIGUSR1 esegue
ls -
l.
$
trap '
'
SIGUSR1
La shell e tutti i processi figli ignorano il segnale SIGUSR1.
1997.10.26 - Scritto da Daniele Giacomini daniele@calion.com (vedi copyright: Appunti Linux).