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


5.6 Ridirigere l’output di print e printf

Finora, l’output di print e printf è stato diretto verso lo standard output, che di solito è lo schermo. Sia print che printf possono anche inviare il loro output in altre direzioni. È quel che si chiama ridirezione.

NOTA: Quando si specifica --sandbox (vedi la sezione Opzioni sulla riga di comando), la ridirezione dell’output verso file, pipe e coprocessi non è consentita.

Una ridirezione è posta dopo l’istruzione print o printf. Le ridirezioni in awk sono scritte come le ridirezioni nei comandi della shell, l’unica differenza è che si trovano all’interno di un programma awk.

Ci sono quattro forme di ridirezione dell’output: output scritto su un file, output aggiunto in fondo a un file, output che fa da input a un altro comando (usando una pipe) e output diretto a un coprocesso. Vengono descritti per l’istruzione print, ma funzionano allo stesso modo per printf:

print elementi > output-file

Questa ridirezione stampa gli elementi nel file di output chiamato output-file. Il nome-file output-file può essere una qualsiasi espressione. Il suo valore è trasformato in una stringa e quindi usato come nome-file (vedi la sezione Espressioni). Quando si usa questo tipo di ridirezione, il file output-file viene cancellato prima che su di esso sia stato scritto il primo record in uscita. Le successive scritture verso lo stesso file output-file non cancellano output-file, ma continuano ad aggiungervi record. (Questo comportamento è differente da quello delle ridirezioni usate negli script della shell.) Se output-file non esiste, viene creato. Per esempio, ecco come un programma awk può scrivere una lista di nomi di persone su un file di nome lista-nomi, e una lista di numeri telefonici su un altro file di nome lista-telefoni:

$ awk '{ print $2 > "lista-telefoni"
>        print $1 > "lista-nomi" }' mail-list
$ cat lista-telefoni
-| 555-5553
-| 555-3412
…
$ cat lista-nomi
-| Amelia
-| Anthony
…

Ogni file in output contiene un nome o un numero su ogni riga.

print elementi >> output-file

Questa ridirezione stampa gli elementi in un file di output preesistente, di nome output-file. La differenza tra questa ridirezione e quella con un solo ‘>’ è che il precedente contenuto (se esiste) di output-file non viene cancellato. Invece, l’output di awk è aggiunto in fondo al file. Se output-file non esiste, viene creato.

print elementi | comando

È possibile inviare output a un altro programma usando una pipe invece di inviarlo a un file. Questa ridirezione apre una pipe verso comando, e invia i valori di elementi, tramite questa pipe, a un altro processo creato per eseguire comando.

L’argomento comando, verso cui è rivolta la ridirezione, è in realtà un’espressione awk. Il suo valore è convertito in una stringa il cui contenuto costituisce un comando della shell che deve essere eseguito. Per esempio, il seguente programma produce due file, una lista non ordinata di nomi di persone e una lista ordinata in ordine alfabetico inverso:

awk '{ print $1 > "nomi.non.ordinati"
       comando = "sort -r > nomi.ordinati"
       print $1 | comando }' mail-list

La lista non ordinata è scritta usando una ridirezione normale, mentre la lista ordinata è scritta inviando una pipe in input al programma di utilità sort.

Il prossimo esempio usa la ridirezione per inviare un messaggio alla mailing list bug-sistema. Questo può tornare utile se si hanno problemi con uno script awk eseguito periodicamente per la manutenzione del sistema:

report = "mail bug-sistema"
print("Script awk in errore:", $0) | report
print("al record numero", FNR, "di", NOME_FILE) | report
close(report)

La funzione close() è stata chiamata perché è una buona idea chiudere la pipe non appena tutto l’output da inviare alla pipe è stato inviato. Vedi la sezione Chiudere ridirezioni in input e in output per maggiori informazioni.

Questo esempio illustra anche l’uso di una variabile per rappresentare un file o un comando; non è necessario usare sempre una costante stringa. Usare una variabile è di solito una buona idea, perché (se si vuole riusare lo stesso file o comando) awk richiede che il valore della stringa sia sempre scritto esattamente nello stesso modo.

print elementi |& comando

Questa ridirezione stampa gli elementi nell’input di comando. La differenza tra questa ridirezione e quella con la sola ‘|’ è che l’output da comando può essere letto tramite getline. Quindi, comando è un coprocesso, che lavora in parallelo al programma awk, ma è al suo servizio.

Questa funzionalità è un’estensione gawk, e non è disponibile in POSIX awk. Vedi la sezione Usare getline da un coprocesso, per una breve spiegazione. Comunicazioni bidirezionali con un altro processo per un’esposizione più esauriente.

Ridirigere l’output usando ‘>’, ‘>>’, ‘|’ o ‘|&’ richiede al sistema di aprire un file, una pipe o un coprocesso solo se il particolare file o comando che si è specificato non è già stato utilizzato in scrittura dal programma o se è stato chiuso dopo l’ultima scrittura.

È un errore comune usare la ridirezione ‘>’ per la prima istruzione print verso un file, e in seguito usare ‘>>’ per le successive scritture in output:

# inizializza il file
print "Non v'allarmate" > "guida.txt"
…
# aggiungi in fondo al file
print "Evitate generatori di improbabilità" >> "guide.txt"

Questo è il modo in cui le ridirezioni devono essere usate lavorando con la shell. Ma in awk ciò non è necessario. In casi di questo genere, un programma dovrebbe usare ‘>’ per tutte le istruzioni print, perché il file di output è aperto una sola volta. (Usando sia ‘>’ che ‘>>’ nello stesso programma, l’output è prodotto nell’ordine atteso. Tuttavia il mischiare gli operatori per lo stesso file è sintomo di uno stile di programmazione inelegante, e può causare confusione in chi legge il programma.)

Come visto in precedenza (vedi la sezione Cose importanti da sapere riguardo a getline), molte tra le più vecchie implementazioni di awk limitano il numero di pipeline che un programma awk può mantenere aperte a una soltanto! In gawk, non c’è un tale limite. gawk consente a un programma di aprire tante pipeline quante ne consente il sistema operativo su cui viene eseguito.

Inviare pipe alla sh

Una maniera particolarmente efficace di usare la ridirezione è quella di preparare righe di comando da passare come pipe alla shell, sh. Per esempio, si supponga di avere una lista di file provenienti da un sistema in cui tutti i nomi-file sono memorizzari in maiuscolo, e di volerli rinominare in modo da avere nomi tutti in minuscolo. Il seguente programma è sia semplice che efficiente:

{ printf("mv %s %s\n", $0, tolower($0)) | "sh" }

END { close("sh") }

La funzione tolower() restituisce la stringa che gli viene passata come argomento con tutti i caratteri maiuscoli convertiti in minuscolo (vedi la sezione Funzioni di manipolazione di stringhe). Il programma costruisce una lista di righe di comando, usando il programma di utilità mv per rinominare i file. Poi invia la lista alla shell per l’elaborazione.

Vedi la sezione Stringhe con apici da passare alla shell per una funzione che può essere utile nel generare righe di comando da passare alla shell.


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