printf(1) The printf function originated in the C programming language, for formatting the output from a program in specific ways. The printf function has migrated from C to a number of other places, including awk, perl, and others. There is also a shell command printf(1). Syntax: printf format_string [ argument ... ] It means "print formatted" This is best interpreted as "print the arguments exactly accorcding to the following format specification string". Note printf(1) is not a filter. The format string The format specification string used by printf has become fairly ubiquitous in computer langauages, so much so that it has its own man page: formats(5). The details of the syntax are described there, rather than in the printf(1) man page. The format string allows printf to produce arbitrarily complex output - which means the format string can be arbitrarily complex. It is composed of a small number of simple elements, though. ** The format string is composed of arbitrary combinations of any of the following components: - Ordinary characters - field format specification strings (aka 'field specifications', or more commonly, 'conversion specifications') - 'Escape sequences' ** The format string may well contain shell metacharacters - so it should be quoted appropriately. Now to examine each component of the format_string in detail. - Ordinary characters Any character that is not part of a format specification string or an escape sequence is an ordinary character. Ordinary characters in the format_string are always printed out verbatim. E.g.: $ printf Hello Hello$ printf(1) printed its format string verbatim. The are no arguments on this command line, just the format string. * Note printf(1) has a fundamental difference from echo(1) and other commands which display arbirary output: * printf will NOT output a Newline at the end of its output unless you explicitly tell it to (using the escape sequence '\n'). (See below). The format string can contain any characters - including whitespace (spaces or tabs, etc.). But note that if it does, the format string must be quoted. E.g.: $ printf Hello there Hello$ The '$' after the printed "Hello" is the next shell prompt. In this case printf(1) took the string "Hello" as its format_string, and the string "there" as its first argument. The shell parses the command line so. "Hello" is the format string. The format string contains no field specification strings - so it uses none of its arguments. The argument "there" is ignored. Note this is not considered an error. All ordinary characters in it are printed, and the command completes normally. Quoting the format string eliminates this problem: $ printf "Hello there" Hello there$ Not quoting the format string can cause insidious problems: $ printf Hello\n Hellon$ ('\n' is the format string escape sequence which means 'print a Newline'). In the above case the shell - not printf(1) sees the '\n', and interprets it. The shell interprets some - but not all - cases of a character preceded by a backslash. Examples are \*, \$, and so on - for all the shell metacharacters ONLY. ** But how the shell interprets non-metacharacters preceded by a backslash is undefined. This means the shell could do literally anything with such a character. What it usually does is return the character unmodified. So in the above example, '\n' is converted to 'n' by the shell. So the expanded command line becomes: printf Hellon Escape sequences are used extensively in format strings (particularly '\n'). So it is always a good idea to quote the format_string appropriately. $ printf "Hello\nthere\nyou!\n" Hello there you! $ - Conversion specifications - Type conversions The printf function (and the printf(1) command) output a string of characters, as you can only write characters to a terminal or printer. Recall that (by default) the shell treats everything on the command line, and the value of any variable, as a string. But in computer programming languages, things are more complicated. A given piece of data may be a character, a string of characters, an integer value (e.g. 13), a floating-point value (e.g. 3.14592671). Programming languages treat all of these differently, and store them in memory differently. In particular, a programming language has to understand how to convert from one type to another (like from the floating point number 3.14 to the string '3.14'). So a program must know what type a piece of data is, in order to know how to convert it to a string of characters for output. That's what conversion specifications are for. It tells the program what 'type' the piece of data is, and thus how to convert it from whatever type it currently is to a string. Actually, the shell stores everything as a string, so really no 'conversions' are performed. But the conversion specification is still required, both to be consistent with printf() everywhere else it exists, and so printf(1) knows how to format a particular numeric string. (See below). printf(1) (and the function printf(3), and the printf() function in awk, etc.) must do the conversion from however the data is represented internally in the program to a string. It then sends the string to stdout. * Type conversions are required for every argument value you want printf to print. ** There MUST be a type conversion specification for EACH argument on the command line. - Type conversion syntax Type conversions are always introduced by the '%' (percent) character, followed by a single letter which indicates what type the data *currently* is. The single letter following the '%' can be one of the following: i - (Signed) decimal integer d - (Signed) decimal integer (same as above; there are two letters that do the same conversion for obscure historical reasons) u - Unsigned decimal integer o - (Unsigned) octal integer x - (Unsigned) hexadecimal (base 16) integer f - Signed decimal floating point number; format nnn.nnnnnn (or similar) e - Signed decimal floating point number; format n.nnnnnn[+/-]enn (scientific notation) E - Signed decimal floating point number; format n.nnnnnn[+/-]Enn (scientific notation) c - A single character (the first if more than one) from the argument is printed. s - String (of characters). % - This handles the special case where you want to print a literal '%' character. '%' is special to printf in that it normally introduces a conversion specification. If you just want to print a literal '%', put the string '%%' in your format string where you want a literal '%' to appear in the output. There are a couple other specifications, for special purposes - which are not covered here. Examples: $ foo=123 $ printf "The value of 'foo' is %s\n" $foo The value of 'foo' is 123 $ printf "The value of 'foo' is %d\n" $foo The value of 'foo' is 123 $ printf "The value of 'foo' is %f\n" $foo The value of 'foo' is 123.000000 $ printf "The value of 'foo' is %E\n" $foo The value of 'foo' is 1.230000E+02 $ $ foo=-123 $ printf "The value of 'foo' is %s\n" $foo The value of 'foo' is -123 $ printf "The value of 'foo' is %d\n" $foo The value of 'foo' is -123 $ printf "The value of 'foo' is %f\n" $foo The value of 'foo' is -123.000000 $ printf "The value of 'foo' is %E\n" $foo The value of 'foo' is -1.230000E+02 $ $ foo=-123.456 $ printf "The value of 'foo' is %s\n" $foo The value of 'foo' is -123.456 $ printf "The value of 'foo' is %d\n" $foo printf: -123.456 not completely converted The value of 'foo' is -123 $ printf "The value of 'foo' is %f\n" $foo The value of 'foo' is -123.456000 $ printf "The value of 'foo' is %E\n" $foo The value of 'foo' is -1.234560E+02 $ Note what happens when foo is not (completely) a number string: $ foo=31foo $ printf "The value of 'foo' is %s\n" $foo The value of 'foo' is 31foo $ printf "The value of 'foo' is %d\n" $foo printf: 31foo not completely converted The value of 'foo' is 31 $ printf "The value of 'foo' is %f\n" $foo printf: 31foo not completely converted The value of 'foo' is 31.000000 $ printf "The value of 'foo' is %E\n" $foo printf: 31foo not completely converted The value of 'foo' is 3.100000E+01 $ ** There must be a conversion specification in the format string for *each* argument on the command line. Technically you don't have to do this - but if you don't, you must understand all the special cases you're now going to be dealing with - which can be tricky. You don't want to have to do that. Examples: $ msg="Please select one of the following options" $ option[1]=a $ option[2]=b $ option[3]=c $ option[4]=d $ default_option=${option[1]} $ printf "%s: [%c%c%c%c]\t[%c] :\n" $msg \ > ${option[1]} ${option[2]} ${option[3]} ${option[4]} \ > $default_option Please: [soot] [f] : options: [abcd] [a] : $ What happened?! Let's look at the expanded command line: $ echo printf "%s: [%c%c%c%c]\t[%c] :\n" $msg \ > ${option[1]} ${option[2]} ${option[3]} ${option[4]} \ > $default_option printf %s: [%c%c%c%c] [%c] : Please select one of the following options a b c d a $ Aha. When $msg was expanded, word splitting made the first argument "Please", the second "select", and so on. The first characters of the following five args are: "s o o t f" - which satisfy the first five '%c' conversion specifications. But there are more six args on the command line (not counting the format string) - in fact there are 12. The first is "Please", the 12th is the final "a". In such a case printf "reuses" the format string specification - starting over from the beginning - as many times as necessary to handle all the arguments on the command line. This is one of those special cases that you don't want to get into. To fix it, we just need to quote any of the arguments which could be broken into more than one word (by word splitting): $ printf "%s: [%c%c%c%c]\t[%c] :\n" \ > "$msg" \ > ${option[1]} ${option[2]} ${option[3]} ${option[4]} \ > $default_option Please select one of the following options: [abcd] [a] : $ It's probably a good idea to quote all args to printf individually to prevent this sort of thing. - Field specifications Using standard conversion specifications may not give you just the format you want: $ cost=12.34 $ printf "Cost is $%f\n" $cost Cost is $12.340000 $ Note a subtle point here. The double quotes allow the shell to "see" and expand any variable references inside the string. In this case the string "$%" is a candidate for parameter expansion. In this case we were "lucky", in that the shell recognizes that "%" is not a valid character in a parameter identifier - AND that "$%" is not a special shell variable (for ksh!). It's better to be right than lucky. So it's wiser to single-quote the format string, unless you have a specific reason not to. That way you won't use up your luck. The capability exists to control not just how the data is converted to a string, but also the format of the string. This is done with a 'field specification'. * A field specification always appears between the '%' character introducing a conversion specification and before the single letter indicating the type conversion. * A field specification may consist of zero or more characters. * A field specification consists of the following parts, in order: - Flags Flags modify the field in some way, such as left justification, zero-filling, etc. - '-' The field is left-justified. Default is right-justified. - '+' Always precede the (numeric) field with a sign character. (This character counts in the field width). - '0' For numeric fields, pad on the left with zeros instead of blanks to the full field width. There are a couple others for special purposes. - Field width The TOTAL number of character positions that will be used to display the data value. For strings, this indicates the minimum number of characters printed. For signed numbers, this includes the sign character. For floating point numbers, this includes the sign character AND the decimal point. For scientific notation, this includes the mantissa sign character, the decimal point, the exponent sign character, the "E" (or "e"), and the (two-character) exponent field. If the converted data value string will not occupy the entire field width, the field is padded on the left with blanks. - Precision The total number of digits that will be printed to the right of the decimal point (for floating point numbers. For strings it indicates the maximum number of characters that will be printed. Field specifications are optional. If not specified, it takes on a default value for a given type conversion. Each part of a field specification is optional. If not specified, they take on default values. * The syntax is: %<"."precision> There may be more than one flag character. The field width must be an unsigned integer. The precision field, if present, must be preceded by a literal period ('.'), and followed immediately by an unsigned integer. Examples: $ printf "Cost is $%09.2f\n" $cost Cost is $000012.34 $ printf "Cost is $%-9.2f\n" $cost Cost is $12.34 $ printf "Cost is $%9.2f\n" $cost Cost is $ 12.34 $ - Escape sequences Escape sequences are used in format strings to represent certain special characters that would otherwise be difficult to represent in a format string. There are a limited number of these. "\\" Prints a literal backslash character. "\a" Rings the terminal "bell". This sends the ASCII character 0x07 to the terminal. "\b" Sends the "backspace" character to the terminal. Usually this will cause the cursor to move one character position to the left. "\f" Formfeed. Ejects the current sheet of paper (for a printer), or scrolls the screen to the top for a terminal, leaving the cursor at the top left of the screen. "\n" Newline. Moves the cursor to beginning of the next line. This one is extensively used. "\r" Carriage return. "\v" Vertical tab. Arguments Arguments to printf can be anything the shell will resolve to a string.