A printf primer


Printf, (print formatted), is a very powerful tool used to format text to make your output more beautiful. It is also very helpful when you are trying to print specific values like hex or octal numbers. In addition, it is sometimes useful to see the actual contents of a variable, including the non-printing characters. In this instance, again, it is useful to print the variable’s value in hex. It is also useful, at times, to be able to format the output of a print statement so you can create columnar output. Again printf can meet this need.


You can code printf with or without parentheses, but I encourage you to always use parentheses. There are some situations where printf requires their use, so if you get in the habit of always using them, you will not run into strange error messages.


The format of a printf statement is:


printf ( “format-specifier”, variable1, variable2, variable3,...variablen)


In this model, the format specifier is contained within a quoted string that may also contain literal text. For example, the statement below prints the decimal value of the variable count:


printf (“The variable count contains the value %d”, count)


There are a series of format specifiers that provide particular capabilities for the command. Each format specifier starts with a % sign.


A format may be modified using one of the following modifiers:


Modifier

Function

-

indicates that the value should be left justified in the field

Example : (“%-4d”,number) would print number, left justified in four spaces.

n

a number indicates the minimum width of the field (if it starts with a zero, it means pad with zero. Example: (“%4d”,number) would print number in a decimal field 4 digits wide, blank padded on the left. Note: If number had 5 digits, all would show, 4 is the minimum.

.n

a decimal after the number indicates maximum width or the number of digits to the right of the decimal place. Example: (“%5.2s”,string) prints 2 characters of the up to 5 in string, and only 2 characters will be printed.




After 0-3 modifiers the format type is specified using one of the following characters:



Format

Meaning

c

a single ASCII character *

d

a decimal number with no decimal point

e

a floating point number in scientific notation (1.00000e+01) Lowercase e

E

a floating point number in scientific notation (1.00000E+01) Uppercase E

f

a floating point number (100010101.337)

g

awk chooses between %e and %f, picking the on that generates the shortest string. Nonsignificant zeros are not printed.

G

awk chooses between %E and %f, picking the one that generates the shortest string. Nonsignificant zeros are not printed.

i

a decimal number (just like %d...i is for integer)

o

an unsigned octal number

s

a string (terminated with a null character)

x

an unsigned hexadecimal number (letters in lower case)

X

an unsigned hexadecimal number (letters in UPPER CASE)



* Note: If the argument used for c is numeric, it is treated as a character and printed, otherwise the argument is thought to be a string, and only the first character of the string is printed.




Printf, being part of awk, only does what you tell it to. Therefore, there are a couple of special characters that control vertical and horizontal spacing:


Escape character

produces

\n

newline character (note, this is a protected n)

\t

Tab (a protected t)






Here are some example printf statements that demonstrate some of these features:

(Note: these are all designed to run within the context of an awk, but the awk is not shown.)


printf( “Dec = %d Oct = %o Hex = %x Char = %c \n”, 20, 20, 20, 20)


produces:

Dec = 20 Oct = 24 Hex = 14 Char =

Note, char 20 is not a printable character.



printf( “Dec = %d Oct = %o Hex = %x Char = %c \n”, 60, 60, 60, 60)


produces:

Dec = 60 Oct = 74 Hex = 3c Char = <



while:


printf( “Dec = %d Oct = %o Hex = %X Char = %c \n”, 60, 60, 60, 60)

Note case ------ ^

produces:

Dec = 60 Oct = 74 Hex = 3C Char = <

Note case ------ ^



To do alignment types of things:


printf (“*%10c*\t%-5d\t%5d\n”, “hello”,10,10)

note -----^

produces

* h* 10 10

The "10" between the % and the c says to make the field 10 bytes wide.

The default alignment is right aligned.

A "c" field specifier says to output ONE character.

-----------

printf (“*%-10c*\t%-5d\t%5d\n”, “hello”,10,10)

note -----^

produces

*h * 10 10

The "10" between the % and the c says to make the field 10 bytes wide.

The minus sign asks for left alignment.


-----------

printf (“*%-10s*\t%-5d\t%5d\n”, “hello”,10,10)

note -----^

produces

*hello * 10 10

The "s" field specifier says to output a string,

the minus sign asks for left justification.

-----------

printf (“*%-10.3s*\t%-5d\t%5d\n”, “hello”,10,10)

note -----^^

produces

*hel * 10 10

The width specifier, "10.3" asks awk to output a field that is 10 characters

wide, but to only output 3 characters into that field. Again, the minus

sign asks for left alignment.


One of the really nice uses for these alignment and width ideas is producing a list of names. For example, if we have the following three names:


Robyn Banks

Dusty Tomes

Manuel Transmission


If you just did a regular


printf("%s, %s\n",$2,$1)


to output them Last name, first name, the output would look something like this:


Banks, Robyn

Tomes, Dusty

Transmission, Manuel


That is OK for just an output for you or I, but if you want to have a better columar layout, you might want all the last names to be the same length. Looking back, you know how to fix that...right...yes, just change the printf format to look like this:


printf("%12s, %s\n",$2,$1)


That way, all the first print fields, (the last names), are 12 characters long. That way, the first characters of each first name would align. Here is what it would look like:


Banks, Robyn

Tomes, Dusty

Transmission, Manuel


That has a different look, doesn't it. Playing with the alignment of data using printf can give you some outstanding output.
Experiment and have fun!