13. Awk printf/sprintf primer

This section describes Awk's printf and sprintf statments.  You probably want to read the first part if you already are familiar with C's printf/sprintf.

Feel free to mail your comments to me at: rog@NOSPAM_rs-freeware.org.

Return to the global table of contents
Frames mode, or No frames


1:  Caveats for those who already have some contact with Printf

2:  "Format strings" and their contents

3:  printf versus sprintf

4:  How to display strings

5:  How to display numbers

6:  Putting it all together


1:  Caveats for those who already have some contact with Printf

If you are already familiar with [s]printf you should know two things.  First, GNU Awk behaves oddly with long integer fields, so you should use %#.0f (where # is the total length of the field) instead of the corresponding %d and %ld sequences. Second, GNU Awk's sprintf doesn't work like C's. Instead of:


sprintf(dest_string, format_string, value . . . value)
GNU Awk asks you to code:


dest_string = sprintf(format_string, value . . . value)

Note also that there's no "[s]scanf" function.

Otherwise, GNU Awk's [s]printf behaves just as you'd expect.

If you're already familiar with [s]printf in C, please ignore the rest of this section.

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

2:  "Format strings" and their contents

A format string is a string that "explains" how a series of variable values are to be printed. It consists of a series of characters.

With the exception of "%%" (which produces a single percent sign), each sequence of characters which begins with a "%" and ends with either an "s" or an "f" is matched to a variable value.

Here's a quick example:


X = sprintf("%s123%s", "abc", "def");

The variable X is now equal to "abc123def".

The sequence "%s" at the beginning got matched to "abc" and the sequence "%s" at the end got matched to "def".

Printf and sprintf are unusual functions in that they take a variable number of arguments, although there must always be at least 1.

Aside from the sequences that start with a "%" and end with either an "s" (string) or "f" (floating point or integer), all other characters are normally rendered "as is".

However there are a few additional sequences:


%% produces a single percent sign
\n produces a new line (or CR/LF in DOS)
\r produces a carriage return
\t produces a tab character
\" produces a double quote
\\ produces a backslash

All but the first should be familiar to JavaScript programmers.

Note that the number of sequences that start with a "%" and end with either "s" or "f" has to be equal to the number of arguments after the format string (otherwise GAwk will complain and the script won't run).

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

3:  printf versus sprintf

printf writes the resulting string to the standard output (remember, Awk has only one output file).

So, for example:


printf("%s\n", "Jello\tHarold!")

prints the string "Jello<tab>Harold!" to the standard output, followed by a newline.  Note that there's a tab character in the middle.

Similarly,


X = sprintf("%s\n", "Jello\tHarold!");

assigns the string 'Jellow<tab>Harold!" to the variable X.

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

4:  How to display strings

Strings are formatted in the following sequence:


"%" Percent sign is always first
"-" Code a minus sign to left-justify
#   Number that specifies the total field width
.#  Use only to truncate the input string
s   Follow with an "s" to specify a string.

Some examples:


X = sprintf("%-20s", "Jello, curdled");

assigns the string:


012345678901234567890
"Jello, curdled      "

to the variable X.  There are 6 spaces padded on the end, because the total length of the field is 20.  Note that I've used a column ruler to emphasize the field length.


X = sprintf("%20s", "Jello, curdled");

assigns the string:


012345678901234567890
"      Jello, curdled"

to the variable X.  The field was right-justified by default, because there was no minus sign after the percent sign.

You can also truncate the string by adding the period and specifier for the input string length.


X = sprintf("%15s", "Jello, hurled!");

assigns the value " Jello, hurled!" to X  (note that "Jello, hurled!" is 14 characters, and because there was no minus sign after the percent sign, the field was right-justified.

But:


X = sprintf("%-12.11s", "Jello, hurled!");

produces "Jello, hurl ".  This is because 3 characters were stripped off the input string, and it was left-aligned in a 12-character field.  So there is exactly one space after "hurl".

Finally, you sometimes need to pad zeros on the left of a string field (for things like customer numbers, which aren't really numbers).

To do this, use a 0 instead of a minus sign after the percent sign (the result is always right-justified, with the padded zeros).

For example:


X = sprintf("%015.11s", "Jello, hurled!");

produces: "0000Jello, hurl"

and


X = sprintf("%015", "Jello, hurled!");

produces: "0Jello, hurled!".

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

5:  How to display numbers

Numbers are formatted in the following sequence:


"%"       Percent sign is always first
"-" | "+" Optional sign specifier
#         Number that specifies the total field width
.#        Precision (digits after decimal--no decimal for 0)
f         Follow with an "f" to specify a number

A sign specifier of "-" forces the field to be left-justified.  If there's a sign, it will go on the left of the data.


X = sprintf("%-4f.0", 20) assigns X to "20  ".
X = sprintf("%-4f.0",-20) assigns X to "-20 "

A sign specifier of "+" will produce a right-justified field with a plus sign on the left for postive values . . . otherwise, it will add a minus sign one the left for negative values.


X = sprintf("%+4f.0", 20) assigns X to " +20"
X = sprintf("%+4f.0",-20) assigns X to " -20"

If there's no sign specifier, you'll get a right-justified field with a blank on the left for positive values, otherwise you'll see a minus sign on the left for negative values.


X = sprintf("%4f.0", 20) assigns X to "  20"
X = sprintf("%4f.0",-20) assigns X to " -20"

If the number that specifies the total field width begins with 0, then zeros will be padded on the left, and any sign will go to the left of those.


X = sprintf("%+04f.0", 20) assigns X to "+020"
X = sprintf("%+04f.0", 20) assigns X to "-020"
X = sprintf("%04f.0" , 20) assigns X to "0020"
X = sprintf("%04f.0" , 20) assigns X to "-020"

However, a minus sign specifier will override this, i.e. the 0 to the left of the field width will have no effect:


X = sprintf("%-04f.0", 20) assigns X to "0020"
X = sprintf("%-04f.0", 20) assigns X to "-020"

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

6:  Putting it all together

Here's a quick example that uses the information in this section.

We'd like to display a customer's name, 4 digit customer number (with zeros padded on the left), their current sales, and the percent change from last month.

If their sales have increased, we'd like to put a plus sign on the percent change field.  If not, we need a minus sign.


C_Name   = "Ng, Lee";      # Customer Name
C_No     = 20;             # Customer Number
C_Sales  = 1340.20;        # Customer Sales
C_Change = 10.20;          # 10.2 % increase

printf("%-10s(#%04.0f) $%10.2f   %+7.2f%% change\n",
       C_Name, C_No,   C_Sales, C_Change);

This produces the following line:


12345678901234567890123456789012345678901234567890
Ng, Lee   (#0020) $   1340.20    +10.20% change

Return to local table of contents
Return to global table of contents
Frames mode, or No frames

Next documentation section