# The joys of printf When I started learning Unix, I got introduced pretty early in the process to the ``echo`` command. Likewise, my initial Python lesson involved the ``print`` function. Picking up C++ and Java introduced me to ``cout`` and ``systemout``. It seemed every language proudly had a convenient one-line method of producing output, and advertised it like it was going out of style. But once I turned the first page of intermediate lessons, I was introduced to ``printf``, a cryptic and mysterious, and surprisingly flexible, function kept hidden from beginners. Going against that puzzling tradition, this article aims to introduce to the world the humble ``printf`` function, and how it can be used in nearly any language you use. ## A brief history of printf The term ``printf`` stands for "print formatted" and may have first appeared in the [ALGOL 68](https://opensource.com/article/20/6/algol68) programming language. Since its inclusion in C, ``printf`` has been reimplemented in C++, Java, Bash, PHP, and quite probably in whatever your favourite (post-C) language happens to be. It's clearly popular, and yet it seems to be regarded as having a complex syntax, especially compared to alternatives such as ``echo`` or ``print`` or ``cout``. For example, here's a simple echo statement in Bash: ``` $ echo hello hello $ ``` Here's the same result using ``printf`` in Bash: ``` $ printf "%s\n" hello hello $ ``` You get a lot of features for that added complexity, though, and that's exactly why ``printf`` is well worth learning. ## printf output The main concept behind ``printf`` is its ability to format its output based on style information *separate* from the content. For instance, there is a collection of special sequences that ``printf`` recognizes as special characters. Your favourite language may have greater or fewer sequences, but common ones include: * \n new line * \r carriage return * \t horizontal tab * \NNN a specific byte with an octal value containing 1 to 3 digits For example: ``` $ printf "\t\123\105\124\110\n" SETH $ ``` In this Bash example, ``printf`` renders a tab character followed by the ASCII characters assigned to a string of four octal values. This is terminated with the control sequence to produce a new line (``\n``). Attempting the same thing with ``echo`` produces something a little more literal: ``` $ printf "\t\123\105\124\110\n" \t\123\105\124\110\n $ ``` Using Python's ``print`` function for the same task reveals that there's more to Python's ``print`` command than you might expect: ``` >>> print("\t\123\n") S >>> ``` Obviously, Python's ``print`` incorporates traditional ``printf`` features as well as the features of a simple ``echo`` or ``cout``. These examples contain nothing more than literal characters, though, and while they're useful in some situations, they're probably the least significant thing about ``printf``. The true power of ``printf`` lies in format specification. ## Format output with printf Format specificiers are characters preceeded by a percent sign (``%``). Common ones include: * %s string * %d digit * %f floating-point number * %o a number in octal These are placeholders in a ``printf`` statement, to be replaced by a value you provide somewhere else in your ``printf`` statement. Where these values are provided depends on the language you're using and its syntax, but here's a simple example in Java: ``` string var="hello\n"; system.out.printf("%s", var); ``` This, wrapped in appropriate boilerplate code and executed, renders: ``` $ ./example hello $ ``` It gets even more interesting, though, when the content of a variable changes. Suppose you want to update your output based on an ever-increasing number: ``` #include int main() { int var=0; while ( var < 100) { var++; printf("Processing is %d%% finished.\n", var); } return 0; } ``` Compiled and run: ``` Processing is 1% finished. [...] Processing is 100% finished. ``` Notice that the double ``%%`` in the code resolves to a single printed ``%`` symbol. ## Limiting decimal places with printf Numbers can get complex, and so ``printf`` offers many options when formatting them. You can limit how many decimal places get printed using the ``%f`` for floating-point numbers. By placing a dot (``.``) along with a limiter number between the percent sign and the ``f``, you tell ``printf`` how many decimals to render. Here's a simple example written in Bash for brevity: ``` $ printf "%.2f\n" 3.141519 3.14 $ ``` Similar syntax applies to other languages. Here's an example in C: ``` #include #include int main() { fprintf(stdout, "%.2f\n", 4 * atan(1.0)); return 0; } ``` For 3 decimal places, use ``.3f``, and so on. ## Adding commas to a number with printf Big numbers can be difficult to parse, so we often break them up with a comma. You can have ``printf`` add commas as needed with by placing an apostrophe (``'``) between the percent sign and the ``d``: ``` $ printf "%'d\n" 1024 1,024 $ printf "%'d\n" 1024601 1,024,601 $ ``` ## Add leading zeros with printf A common use for ``printf`` is to impose a specific format upon numbers in file names. For instance, if you have ten sequential files on a computer, the computer may sort ``10.jpg`` as being before ``1.jpg``, which is probably not your intent. When writing out to a file programmatically, you can use ``printf`` to form the file name with leading zero characters. Here's an example in Bash for brevity: ``` $ printf "000%d.jpg\n" {1..10} 0001.jpg 0002.jpg [...] 00010.jpg ``` ## Using printf As you can tell from these ``printf`` examples, the inclusion of control characters, especially ``\n``, can be tedious, and the syntax is relatively complex. This is the very reason shortcuts like ``echo`` and ``cout`` were developed, of course. However, if you force yourself to use ``printf`` every now and again, you'll get used to the syntax and it gets to be second nature. I don't see any reason ``printf`` should be your *first* choice for printing statements during your everyday activities, but it's a great tool to be comfortable enough with that it doesn't slow you down when you have a sudden need for it. Take some time to learn ``printf`` in whatever your language of choice is, and use it when you need it. It's a powerful tool you won't regret having at your fingertips.