It’s only words, and words are all I have…

Using printf in BASH

In Linux we write a lot of shell scripts to help us automate things or ease complex tasks. Sometimes we need to display some information on the screen, so it’s pretty common to find quite a few echo statements lying about, like so:

echo "I'm sorry Dave, I can't do that."

The command is also useful when we want to examine the contents of a variable from the command line. For example, to see the exit code of the most recently run command:

$ echo $?

But sometimes the echo command doesn’t give us enough control over the display of data. That’s why bash includes the printf command, for formatted printing. printf can be used to display a simple string, but be careful:

$ printf 'Daisy, Daisy, give me your answer, do.'
Daisy, Daisy, give me your answer, do.$

You might notice that the prompt appears immediately after the output. If you’re going to exercise greater control over the way that data will be displayed, you’ll have to be responsible for more than just the letters that you want on the screen. printf can be pretty literal, so we’ll need to close our string with a newline, a symbol that tells printf to move on to the next line when it’s done.

$ printf 'Open the pod bay doors, HAL.\n'
Open the pod bay doors, HAL.

The backslash-n character combination represents a newline signal to bash, so it will go on to the next line.

Formatted output goes a bit further than this, though. We can print text from variables using special placeholders in the string.

$ printf 'My name is %s.\n' $USERNAME
My name is rob.

The %s is a placeholder for a string of plain text characters. It will be filled in with the data that follows the formatted string. You can have as many of those as you need.

$ printf 'User %s on host %s\n' $USERNAME $HOSTNAME
User rob on host pluto

There are actually several different kinds of placeholders available to printf, but the most common are %s for strings, %d or %i for integers, %f for floating point values, and %x for hexadecimal numbers. That last one comes in really handy when you need to find the hex equivalent of some decimal number:

$ printf '%x\n' 226

Since this command is all about formatting we should take a look at how we can do that. By interpolating a number between the percent sign and the place holder identifier we can specify a column width for the data to occupy. A negative number will justify the output to the right and a positive number will justify to the left.

$ printf '| %-7s | %8s |\n| %-7s | %8s |\n' \
        'User' 'Host' $USERNAME $HOSTNAME
| User    |     Host |
| rob     |    pluto |

As you can see this can be very useful for displaying tabular data.

$ tail -3 /etc/passwd | \
        cut -f1,3,6 -d: --output-delimiter=' ' | \
        xargs printf '%-8s %5d %s\n'
rob       1000 /home/rob
dave      1001 /home/dave
nobody   65534 /nonexistent

Even better, we can use a modifier to round off a floating point number.

$ pi=3.141592653589793238
$ printf 'The value of pi is about %.5f.\n' $pi
The value of pi is about 3.14159.

Pi was rounded to five decimal places. Note the dot before the number 5. This indicates that you want decimal precision rather than a field width. To demonstrate that printf is truly rounding the number and not just truncating it, try it with six decimal places:

$ printf 'The value of pi is about %.6f.\n' $pi
The value of pi is about 3.141593.

The best way to get to know printf is to experiment with it. Take some of these ideas I’ve given you and see what you can come up with.

Be seeing you.

One thought on “It’s only words, and words are all I have…

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s