Successivo: , Precedente: , Su: Stampare   [Contenuti][Indice]


5.9 Chiudere ridirezioni in input e in output

Se lo stesso nome-file o lo stesso comando di shell è usato con getline più di una volta durante l’esecuzione di un programma awk (vedi la sezione Richiedere input usando getline), il file viene aperto (o il comando viene eseguito) solo la prima volta. A quel punto, il primo record in input è letto da quel file o comando. La prossima volta che lo stesso file o comando è usato con getline, un altro record è letto da esso, e così via.

Analogamente, quando un file o una pipe sono aperti in output, awk ricorda il nome-file o comando a essi associato, e le successive scritture verso lo stesso file o comando sono accodate alle precedenti scritture. Il file o la pipe rimangono aperti fino al termine dell’esecuzione di awk.

Questo implica che sono necessari dei passi speciali per rileggere nuovamente lo stesso file dall’inizio, o per eseguire di nuovo un comando di shell (invece che leggere ulteriore output dal precedente comando). La funzione close() rende possibile fare queste cose:

close(NOME_FILE)

o:

close(comando)

l’argomento NOME_FILE o comando può essere qualsiasi espressione, il cui valore dev’essere esattamente uguale alla stringa usata per aprire il file o eseguire il comando (spazi e altri caratteri “irrilevanti” inclusi). Per esempio, se si apre una pipe così:

"sort -r nomi" | getline pippo

essa va chiusa in questo modo:

close("sort -r nomi")

Una volta eseguita questa chiamata di funzione, la successiva getline da quel file o comando, o la successiva print o printf verso quel file o comando, riaprono il file o eseguono nuovamente il comando. Poiché l’espressione da usare per chiudere un file o una pipeline deve essere uguale all’espressione usata per aprire il file o eseguire il comando, è buona norma usare una variabile che contenga il nome-file o il comando. Il precedente esempio cambia come segue:

sortcom = "sort -r nomi"
sortcom | getline pippo
…
close(sortcom)

Questo aiuta a evitare nei programmi awk errori di battitura difficili da scoprire. Queste sono alcune delle ragioni per cui è bene chiudere un file di output:

Se si usano file in numero superiore a quelli che il sistema permette di mantenere aperti, gawk tenta di riutilizzare i file aperti disponibili fra i file-dati. La possibilità che gawk lo faccia dipende dalle funzionalità del sistema operativo, e quindi non è detto che questo riesca sempre. È quindi sia una buona pratica che un buon suggerimento per la portabilità quello di usare sempre close() sui file, una volta che si è finito di operare su di essi. In effetti, se si usano molte pipe, è fondamentale che i comandi vengano chiusi, una volta finita la loro elaborazione. Per esempio, si consideri qualcosa del tipo:

{
    …
    comando = ("grep " $1 " /qualche/file | un_mio_programma -q " $3)
    while ((comando | getline) > 0) {
        elabora output di comando
    }
    # qui serve close(comando)
}

Questo esempio crea una nuova pipeline a seconda dei dati contenuti in ogni record. Senza la chiamata a close() indicata come commento, awk genera processi-figlio per eseguire i comandi, fino a che non finisce per esaurire i descrittori di file necessari per creare ulteriori pipeline.

Sebbene ogni comando sia stato completato (come si deduce dal codice di fine-file restituito dalla getline), il processo-figlio non è terminato;28 inoltre, e questo è ciò che più ci interessa, il descrittore di file per la pipe non è chiuso e liberato finché non si chiama close() o finché il programma awk non termina.

close() non fa nulla (e non emette messaggi) se le viene fornito come argomento una stringa che non rappresenta un file, una pipe o un coprocesso che sia stato aperto mediante una ridirezione. In quel caso, close() restituisce un codice di ritorno negativo, che indica un errore. Inoltre, gawk imposta ERRNO a una stringa che indica il tipo di errore.

Si noti anche che ‘close(NOME_FILE)’ non ha effetti “magici” sul ciclo implicito che legge ogni record dei file indicati nella riga di comando. Si tratta, con ogni probabilità, della chiusura di un file che non era mai stato aperto con una ridirezione, e per questo awk silenziosamente non fa nulla, tranne impostare un codice di ritorno negativo.

Quando si usa l’operatore ‘|&’ per comunicare con un coprocesso, è talora utile essere in grado di chiudere un lato della pipe bidirezionale, senza chiudere l’altro lato. Questo è possibile fornendo un secondo argomento a close(). Come in ogni altra invocazione di close(), il primo argomento è il nome del comando o file speciale usato per iniziare il coprocesso. Il secondo argomento dovrebbe essere una stringa, con uno dei due valori "to" [a] oppure "from" [da]. Maiuscolo/minuscolo non fa differenza. Poiché questa è una funzionalità avanzata, la trattazione è rinviata alla Comunicazioni bidirezionali con un altro processo, che ne parla più dettagliatamente e fornisce un esempio.

Usare il codice di ritorno di close()

In molte versioni di Unix awk, la funzione close() è in realtà un’istruzione. (a.b.) È un errore di sintassi tentare di usare il codice di ritorno da close():

comando = "…"
comando | getline info
retval = close(comando)  # errore di sintassi in parecchi Unix awk

gawk gestisce close() come una funzione. Il codice di ritorno è -1 se l’argomento designa un file che non era mai stato aperto con una ridirezione, o se c’è un problema di sistema nella chiusura del file o del processo. In tal caso, gawk imposta la variabile predefinita ERRNO a una stringa che descrive il problema.

In gawk, a partire dalla versione 4.2, quando si chiude una pipe o un coprocesso (in input o in output), il codice di ritorno è quello restituito dal comando, come descritto in Tabella 5.1.29. Altrimenti, è il codice di ritorno dalla chiamata alle funzione di sistema close() o alla funzione C fclose() se si sta chiudendo un file in input o in output, rispettivamente. Questo valore è zero se la chiusura riesce, o -1 se non riesce.

SituazioneValore restituito da close()
Uscita normale dal comandoIl codice di ritorno del comando
Uscita dal comando per signal256 + numero del segnale assassino
Uscita dal comando per signal con dump512 + numero del segnale assassino
Errore di qualsiasi tipo-1

Tabella 5.1: Codici di ritorno dalla close() di una pipe

Lo standard POSIX è molto generico; dice che close() restituisce zero se è terminata correttamente, e un valore diverso da zero nell’altro caso. In generale, implementazioni differenti variano in quel che restituiscono chiudendo una pipe; quindi, il codice di ritorno non può essere usato in modo portabile. (a.b.) In modalità POSIX (vedi la sezione Opzioni sulla riga di comando), gawk restituisce solo zero quando chiude una pipe.


Note a piè di pagina

(28)

La terminologia tecnica è piuttosto macabra. Il processo-figlio terminato è chiamato “zombie,” e la pulizia alla fine dello stesso è chiamata “reaping” [mietitura].

(29)

Prima della versione 4.2, il codice di ritorno dopo la chiusura di una pipe o di un coprocesso era una cifra di due byte (16-bit), contenente il valore restituito dalla chiamata di sistema wait()


Successivo: , Precedente: , Su: Stampare   [Contenuti][Indice]