Introduzione

Tipicamente, quando scriviamo script bash, usiamo echo per stampare sullo standard output. echo è un comando semplice ma è limitato nelle sue capacità.
Per avere un maggiore controllo sulla formattazione dell'output, utilizzare il comando printf.

Il comando printf formatta e stampa i suoi argomenti, in modo simile alla funzione C printf().

Comando printf

printf è una shell integrata in Bash e in altre shell popolari come Zsh e Ksh. Esiste anche un file binario autonomo /usr/bin/printf, ma la versione integrata della shell ha la precedenza. Tratteremo la versione integrata di Bash di printf.

La sintassi per il comando printf è la seguente:

printf [-v var] format [arguments]

L'opzione -v permette al comando printf di non stampare l'output ma di assegnarlo a una variabile.

Il parametro format è una stringa che può contenere tre diversi tipi di oggetti:

  • Caratteri normali che sono semplicemente stampati sull'output così come sono.
  • Caratteri con backslash che vengono interpretati e quindi stampati.
  • Specifiche di conversione che descrivono il formato e sono sostituite dai valori dei rispettivi argomenti che seguono la stringa di formato.

Il comando accetta un numero qualsiasi di arguments. Se vengono forniti più arguments di formati, la stringa format viene riutilizzata per  tutti gli arguments. Se vengono forniti meno arguments rispetto ai format, i formati numeri extra vengono impostati su zero mentre i formati stringa extra sono impostati su stringa null.

Di seguito sono riportati alcuni punti da considerare quando si passano gli argomenti al comando printf:

  • La shell sostituirà tutte le variabili, i caratteri wildcard e i caratteri speciali prima di passare gli argomenti al comando printf.
  • Quando si usano virgolette singole '' il valore letterale di ciascun carattere racchiuso tra virgolette verrà conservato. Variabili e comandi non verranno espansi.

Un tipico esempio di utilizzo di printf è simile a:

printf "Open issues: %s\nClosed issues: %s\n" "34" "65"
Open issues: 34
Closed issues: 65

La stringa Open issues: %s\nClosed issues: %s\n è il format mentre "34" e "65" sono arguments. La stringa di formato contiene due caratteri di nuova riga (\n) e due identificatori di formato (%s) che vengono sostituiti con gli argomenti.

Il comando printf non aggiunge un carattere di nuova riga (\n) alla fine della riga.

Caratteri Backslash-escaped

I caratteri con escape backslash vengono interpretati quando utilizzati nella stringa di formato o in un argomento corrispondente a un %b identificatore di conversione. Ecco un elenco di caratteri di escape più comuni:

  • \\ - Visualizza un carattere barra rovesciata.
  • \b - Visualizza un carattere backspace.
  • \n - Visualizza una nuova riga.
  • \r - Visualizza un ritorno a capo.
  • \t - Visualizza una scheda orizzontale.
  • \v - Visualizza una scheda verticale.

Specifiche di conversione

Una specifica di conversione ha la forma seguente:

%[flags][width][.precision]specifier

Ogni specifica di conversione inizia con il segno di percentuale (%), include modificatori e fini opzionali con una delle seguenti lettere che rappresentano il tipo di dati (specifier) dell'argomento corrispondente: aAbcdeEfgGioqsuxX.

Tipi di identificatori di conversione

La conversione del tipo specifier è un carattere che specifica come interpretare l'argomento corrispondente. Questo carattere è obbligatorio ed è posizionato dopo i campi opzionali.

Di seguito è riportato un elenco che mostra tutti i tipi di conversioni e ciò che fanno:

  • %b - Stampa l'argomento durante l'espansione delle sequenze di escape barra rovesciata (backslash).
  • %q - Stampa l'argomento citato dalla shell, riutilizzabile come input.
  • %d, %i - Stampa l'argomento come intero decimale con segno.
  • %u - Stampa l'argomento come intero decimale senza segno.
  • %o - Stampa l'argomento come un numero intero ottale senza segno.
  • %x, %X - Stampa l'argomento come intero esadecimale senza segno. %x stampa lettere minuscole e %X stampa maiuscole.
  • %e, %E - Stampa l'argomento come un numero a virgola mobile in notazione esponenziale. %e stampa lettere minuscole e %E stampa maiuscole.
  • %a, %A - Stampa l'argomento come un numero a virgola mobile in notazione frazionata esadecimale. %astampa lettere minuscole e %Astampa maiuscole.
  • %g, %G - Stampa l'argomento come un numero a virgola mobile in notazione normale o esponenziale, a seconda di quale sia più appropriato per il valore e la precisione dati. %g stampa lettere minuscole e %G stampa maiuscole.
  • %c - Stampa l'argomento come un singolo carattere.
  • %f - Stampa l'argomento come numero in virgola mobile.
  • %s - Stampa l'argomento come una stringa.
  • %%- Stampa un %simbolo letterale .

Un numero senza segno rappresenta zero e numeri positivi, mentre un numero con segno rappresenta numeri negativi, zero e positivi.

Il seguente comando stampa il numero 100 in tre diversi sistemi di numerazione:

printf "Decimal: %d\nHex: %x\nOctal: %o\n" 100 100 100
Decimal: 100
Hex: 64
Octal: 144

Direttive sui flags

I flag sono i primi modificatori opzionali e vengono utilizzati per impostare la giustificazione, gli zeri iniziali, i prefissi, ecc.

Ecco i più comuni:

  • - - Allinea a sinistra il testo stampato all'interno del campo. Per impostazione predefinita, il testo è allineato a destra.
  • + - Prefisso i numeri con un segno + o -. Per impostazione predefinita, solo i numeri negativi sono preceduti da un segno negativo.
  • 0 - Pad numeri con zeri iniziali anziché spazio.
  • vuoto - Prefisso i numeri positivi con uno spazio vuoto e i numeri negativi con un segno meno (-).
  • # - Un formato alternativo per i numeri.

Direttiva Width

La direttiva width viene posizionata dopo qualsiasi flag e specifica il numero minimo di caratteri che dovrebbe comportare la conversione.

Se la larghezza del testo emessa è inferiore alla larghezza specificata, viene riempita con spazi. La larghezza può essere specificata come un numero intero decimale non negativo o un asterisco (*).

Ecco un esempio:

printf "%20s %d\n" Mark 305

%20s significa impostare il campo di almeno 20 caratteri. Gli spazi vengono aggiunti prima del testo perché, per impostazione predefinita, l'output è giustificato a destra. Per allineare il testo a sinistra, utilizzare il flag - (%-20s).

      Mark 305

Quando un asterisco (*) viene utilizzato come direttiva width, la larghezza del campo di conversione viene impostata da un argomento width che precede l'argomento formattato.

Nell'esempio seguente impostiamo la larghezza su 10:

printf "%0*d" 10 5

0 è un flag che riempie il numero con zeri iniziali anziché spazi vuoti. Il testo di output avrà almeno 10 caratteri:

0000000005

Direttiva Precision

Il modificatore .precision è costituito da un punto (.) seguito da un numero intero positivo o da un asterisco (*) che, in base al tipo di specificatore, imposta il numero di caratteri stringa o cifra o il numero di cifre decimali da stampare.

.precision ha il seguente effetto:

  • Se il tipo di conversione è un numero intero, precision specifica il numero minimo di cifre da stampare. Se il numero di cifre nell'argomento è inferiore a precision, vengono stampati gli zeri iniziali.
  • Se il tipo di conversione è in virgola mobile, precision specifica il numero di cifre che seguono il carattere in virgola decimale. Di default precision è di 6.
  • Se il tipo di conversione è una stringa, precision specifica il numero massimo di caratteri da stampare. Se il numero di caratteri nell'argomento è maggiore di precision, i caratteri in eccesso vengono troncati.

Ecco un esempio che mostra come arrotondare un numero in virgola mobile a 3 decimali:

printf "%.3f" 1.61803398
1.618

Quando precision è impostata su un asterisco (*), il suo valore viene impostato dall'argomento precision che precede l'argomento che viene formattato.

printf "%.*f" 3 1.61803398
1.618

Conclusione

Il comando printf accetta un formato e argomenti e stampa un testo formattato.