Writing to a Terminal

It’s one of the most basic parts of interacting with a program. The program writes something to the screen, and you read it. Even taking into consideration the Unix-derived and Linux-upheld convention of command-line programs being as terse as possible—many only write to the terminal if something goes wrong. Telling the user what is happening, or is about to happen, or has just happened is an essential programming primitive.

The Bash shell has the echo command that can write text to the terminal window. It can handle variables and display their values if they are included in the string, and you can use it in scripts or on the command line. So why does printf even exist? Doesn’t echo have the text writing thing covered? Well, printf offers functionality beyond the plain-vanilla act of writing strings to terminal windows. It allows you to format the output with great flexibility, and it has other tricks too.

The Bash printf command is modeled on the printf function from the C language, but there are differences. If you know C, you’ll need to watch out for those differences.

Writing Basic Strings

Let’s see how echo and printf differ when they write strings to the terminal.

The echo command prints all the words but printf only prints the first word. Also, there’s no new line printed by printf. The output is butted right up against the command prompt. But, first things first, to have printf act on all the words, they need to be quoted.

That’s better. We’ve got all the words being printed but we still don’t get a new line. That’s because with printf you only get a new line if you ask for one. That might seem like a pain but it lets you decide whether to include one or not. To cause printf to issue a new line, you need to include “\n” in your string. This is the “newline” escape sequence.

Sometimes you’ll use a newline and sometimes you won’t. Here’s a case where one printf statement uses a new line and the other doesn’t.

Because the first printf doesn’t print a new line, the output from the second printf is positioned immediately after “How-To” and on the same line. The second printf does use \n to print a new line. This makes the command prompt appear on the line below the printed text.

RELATED: How to Process a File Line by Line in a Linux Bash Script

Other Escape Characters

Here are some more escape characters you can use. You’ve already seen “\n” in action.

\n: Moves down to a new line. \r: Prints a carriage return. This sends the output cursor back to the start of the current line. \t: Prints a tab character. \v: prints a vertical tab space. \: Prints a backslash character. \”: Prints a quotation character. \b: Prints a backspace character.

The carriage return escape character moves the cursor back to the start of the current line.

The printf command processes its input from left to right. The string is printed as normal text until printf encounters the “\r” escape character. The output cursor is moved back to the start of the current line.

Processing of the string resumes with the letter immediately behind the “\r” character. Processing the remainder causes printf to print “Money”, overwriting the word “Honey.”

The quotation mark “"” is used to quote strings, and the backslash “\” character denotes escape sequences. If you want to print these characters you need to escape them with a backslash. This tells printf to treat them as literal characters.

Using Variables

Using variables with printf is very similar to using them with echo . To include a variable, like this environment variable, precede it with the dollar sign “$” as usual.

RELATED: How to Work with Variables in Bash

Format Strings

Format strings are strings that define the format of the output. You provide text and other values as arguments for the format string to operate on.

The format string can include text, escape sequences, and format specifiers. Format specifiers tell printf what type of argument to expect, such as strings, integers, or characters.

These are the most common format specifiers. They are all preceded by a percent “%” sign. To print a percent sign, you use two percent signs together “%%.”

%s: Prints a string. %c: Prints a single character. %d: Prints an integer. %f: prints a floating point number. %u: Prints an unsigned integer. %o: Prints a value in octal. %x: Prints a value in hexadecimal, in lowercase. %X: Prints a value in hexadecimal, in uppercase. %e: Prints a floating point number in scientific notation, in lowercase. %E: Prints a floating point number in scientific notation, in uppercase. %%: Prints a percent “%” symbol.

The format string in the first command includes some text of its own. We pass the string “Geek” as an argument to printf. It is matched to, and printed by, the “%s” format specifier. Note that there is just a space between the format string and the argument string. In C, you’d need a comma to separate them but with the Bash version of printf using a space is sufficient.

The second format string contains only format specifiers and the newline escape sequence. The three string arguments are consumed by each of the “%s” format specifiers in turn. Again, in C, you need to put a comma between each argument but the Bash printf lets us forget about that.

To print different types of arguments you simply use the appropriate format specifier. Here’s a quick number conversion routine built using printf. We’ll print the value 15 in decimal, octal, and hexadecimal notation.

Let’s trim that back a bit so that the example is less cluttered.

Most of us are used to seeing hexadecimal values in uppercase and with values less than 0x10 printed with a leading zero. We can achieve that by using the uppercase hexadecimal format specifier “%X” and putting a width specifier between the percent sign “%” and the “X” character.

This tells printf the width of the field that the argument should be printed in. The field is padded with spaces. With this format, two-digit values would be printed without any padding.

We now get an uppercase value, printed with a leading space. We can make printf pad the field with zeroes instead of spaces by putting a zero in front of the two:

The precision specifier allows you to set the number of decimal points to include in the output.

This makes it easy to produce tables of results with neatly aligned output. This next command also demonstrates another of the quirks of Bash printf. If there are more arguments than there are format specifiers, the arguments are fed into the format string in batches until all of the arguments have been used up. The size of the batch that is processed at a time is the number of format specifiers in the format string. In C, extra arguments in printf function calls are ignored.

You can use the width and precision specifiers with strings too. This command prints the strings in a 10 character wide field.

By default, values are right-justified in their fields. To left-justify them, use a minus sign “-” immediately behind the percent “%” sign.

The precision specifier can be used to set the maximum number of characters that are printed. We’re using the colon characters “:” to show the limits of the width field. Not how the word “Umbrellas” is truncated.

The width specifier can even be passed in as an argument. Use an asterisk “*” instead of a numerical specifier, and pass the width as an integer argument.

Other Tricks and Quirks

The format specifiers inside the format string will work with values of the appropriate type, whether they’re provided on the command line as regular arguments or whether they’re generated as the output of an expression.

This prints the sum of two numbers:

This command prints the number of directories in the current working directory:

This printf command prints a string returned from a call to another command.

If a string format specifier “%s” is not supplied with an argument printf prints nothing.

If a string format specifier “%s” is provided with a numerical value by mistake, it prints it as though it were a string and doesn’t complain. Don’t try this with the C printf—very bad things will happen. Your program will probably crash. But the Bash printf handles it without complaining.

If an integer format specifier “%d” receives no argument it’ll print zero.

If an integer format specifier “%d” receives a string argument by mistake, Bash will print an error message and printf will print zero.

Awkward symbols can be generated by using their Unicode number or “code point.” These are escaped using the letter “u” followed by their Unicode value.

To include escape sequences in argument strings, you must use the “%b” format specifier in the format string, not the “%s” string format specifier.

The first printf statement doesn’t process the Unicode value and it doesn’t recognize the newline escape sequence. The second printf statement uses the “%b” format specifier. This correctly handles the Unicode character and a new line is printed.

RELATED: What Are Character Encodings Like ANSI and Unicode, and How Do They Differ?

Horses for Courses

Sometimes all you need to do is echo some text to the terminal window. But when you need to apply some positioning and formatting, printf is the right tool for the job.