commands:builtin:printf

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
commands:builtin:printf [2012/02/27 00:07]
pi3832 [Using printf inside of awk]
commands:builtin:printf [2016/11/30 15:39] (current)
medievalist [differences from awk printf]
Line 1: Line 1:
 ====== The printf command ====== ====== The printf command ======
  
-FIXME incomplete +<div center round todo box 70%> 
-FIXME Stranger, this is a very big topic that needs experience - please extend the descriptions and correct the details if you can! +FIXME Stranger, this is a very big topic that needs experience - please ​fill in missing information, ​extend the descriptionsand correct the details if you can! 
 +</​div>​ 
 +<div center round tip 70%>
 __**Attention:​**__ This is about the Bash-builtin command ''​printf''​ - however, the description should be nearly identical for an external command that follows POSIX(r). __**Attention:​**__ This is about the Bash-builtin command ''​printf''​ - however, the description should be nearly identical for an external command that follows POSIX(r).
 +
 +[[http://​www.gnu.org/​software/​gawk/​manual/​gawk.html#​Printf|GNU Awk]] expects a comma after the format string and between each of the arguments of a **printf** command. ​ For examples, see: [[printf?&#​using_printf_inside_of_awk|code snippet]].
 +</​div>​
  
 Unlike other documentations,​ I don't want to redirect you to the manual page for the ''​printf()''​ C function family. However, if you're more experienced,​ that should be the most detailed description for the format strings and modifiers. Unlike other documentations,​ I don't want to redirect you to the manual page for the ''​printf()''​ C function family. However, if you're more experienced,​ that should be the most detailed description for the format strings and modifiers.
  
-Due to mutual exclusive ​historical implementations of the ''​echo''​ command, POSIX(r) recommends ​to use ''​printf'' ​rather than ''​echo''​. +Due to conflicting ​historical implementations of the ''​echo''​ command, POSIX(r) recommends ​that ''​printf'' ​is preferred over ''​[[commands:​builtin:​echo|echo]]''​.
- +
- +
  
 ===== General ===== ===== General =====
Line 29: Line 30:
 Thus, a typical ''​printf''​-call looks like: Thus, a typical ''​printf''​-call looks like:
 <​code>​ <​code>​
-printf "​Surname:​ %s\nName: %s\n" "​$SURNAME"​ "$LASTNAME"+printf "​Surname:​ %s\nName: %s\n" "​$SURNAME"​ "$FIRSTNAME"
 </​code>​ </​code>​
 where ''"​Surname:​ %s\nName: %s\n"''​ is the format specification,​ and the two variables are passed as arguments, the ''​%s''​ in the formatstring points to (for every format specifier you give, ''​printf''​ awaits one argument!). where ''"​Surname:​ %s\nName: %s\n"''​ is the format specification,​ and the two variables are passed as arguments, the ''​%s''​ in the formatstring points to (for every format specifier you give, ''​printf''​ awaits one argument!).
- 
-<note tip>​[[http://​www.gnu.org/​software/​gawk/​manual/​gawk.html#​Printf|GNU Awk]] expects a comma after the format string and between each of the arguments of a **printf** command.</​note>​ 
  
 ==== Options ==== ==== Options ====
Line 50: Line 49:
 ...where the echo can of course be replaced with any arbitrary command. If you must, either specify a hard-coded format string or use <​nowiki>​--</​nowiki>​ to signal the end of options. The exact same issue also applies to [[commands/​builtin/​read | read]], and a similar one to [[commands/​builtin/​mapfile | mapfile]], though performing expansions into their arguments is less common. ...where the echo can of course be replaced with any arbitrary command. If you must, either specify a hard-coded format string or use <​nowiki>​--</​nowiki>​ to signal the end of options. The exact same issue also applies to [[commands/​builtin/​read | read]], and a similar one to [[commands/​builtin/​mapfile | mapfile]], though performing expansions into their arguments is less common.
 </​note>​ </​note>​
 +
 ==== Arguments ==== ==== Arguments ====
  
Line 64: Line 64:
 __**If more arguments than format specifiers**__ are present, then the format string is re-used until the last argument is interpreted. If fewer format specifiers than arguments are present, then number-formats are set to zero, while string-formats are set to null (empty). __**If more arguments than format specifiers**__ are present, then the format string is re-used until the last argument is interpreted. If fewer format specifiers than arguments are present, then number-formats are set to zero, while string-formats are set to null (empty).
  
-Also, to minimize surprises, when ''​printf''​ expects an argument, give it one, not more. I'm talking about shell word splitting, ​please read [[syntax:​words | this article]] ​if you don't know what I mean.+Take care to avoid [[syntax:​expansion:​wordsplit | word splitting]]as accidentally passing the wrong number of arguments can produce wildly different and unexpected results. See [[syntax:​words | this article]].
  
 <note warning> <note warning>
 __**Again, attention:​**__ When a numerical format expects a number, the internal ''​printf''​-command will use the common Bash arithmetic rules regarding the base. A command like the following example **will** throw an error, since ''​08''​ is not a valid octal number (''​00''​ to ''​07''​!):​ __**Again, attention:​**__ When a numerical format expects a number, the internal ''​printf''​-command will use the common Bash arithmetic rules regarding the base. A command like the following example **will** throw an error, since ''​08''​ is not a valid octal number (''​00''​ to ''​07''​!):​
 <​code>​ <​code>​
-printf ​"%d\n" ​08+printf ​'%d\n' ​08
 </​code>​ </​code>​
 </​note>​ </​note>​
Line 75: Line 75:
 ==== Format strings ==== ==== Format strings ====
  
-FIXME incomplete +The format string interpretion is derived from the C ''​printf()''​ function family. Only format specifiers that end in one of the letters ''​diouxXfeEgGaAcs''​ are recognized.
- +
-The format string interpretion is derived from the C ''​printf()''​ function family. Only format specifiers that end in one of the letters ''​diouxXfeEgGcs''​ are recognized.+
  
 To print a literal ''​%''​ (percent-sign),​ use ''<​nowiki>​%%</​nowiki>''​ in the format string. To print a literal ''​%''​ (percent-sign),​ use ''<​nowiki>​%%</​nowiki>''​ in the format string.
Line 89: Line 87:
   * ...   * ...
  
-^ Format ​         ^ Description ​                                                                                                                                                                                                               +^Format^Description^ 
-| ''​%b'' ​         | Print the associated argument while interpreting backslash escapes in there                                                                                                                                                +|''​%b''​|Print the associated argument while interpreting backslash escapes in there| 
-| ''​%q'' ​         | Print the associated argument **shell-quoted**,​ reusable as input                                                                                                                                                          +|''​%q''​|Print the associated argument **shell-quoted**,​ reusable as input| 
-| ''​%d'' ​         | Print the associated argument as **signed decimal** number ​                                                                                                                                                                ​+|''​%d''​|Print the associated argument as **signed decimal** number| 
-| ''​%i'' ​         | Same as ''​%d'' ​                                                                                                                                                                                                            ​+|''​%i''​|Same as ''​%d''​| 
-| ''​%o'' ​         | Print the associated argument as **unsigned octal** number ​                                                                                                                                                                ​+|''​%o''​|Print the associated argument as **unsigned octal** number| 
-| ''​%u'' ​         | Print the associated argument as **unsigned decimal** number ​                                                                                                                                                              ​+|''​%u''​|Print the associated argument as **unsigned decimal** number| 
-| ''​%x'' ​         | Print the associated argument as **unsigned hexadecimal** number with lower-case hex-digits (a-f)                                                                                                                          +|''​%x''​|Print the associated argument as **unsigned hexadecimal** number with lower-case hex-digits (a-f)| 
-| ''​%X'' ​         | Same as ''​%x'',​ but with upper-case hex-digits (A-F)                                                                                                                                                                       ​+|''​%X''​|Same as ''​%x'',​ but with upper-case hex-digits (A-F)| 
-| ''​%f'' ​         | Interpret and print the associated argument as **floating point** number ​                                                                                                                                                  ​+|''​%f''​|Interpret and print the associated argument as **floating point** number| 
-| ''​%e'' ​         | Interpret the associated argument as **double**, and print it in ''<​N>​±e<​N>''​ format ​                                                                                                                                      ​+|''​%e''​|Interpret the associated argument as **double**, and print it in ''<​N>​±e<​N>''​ format| 
-| ''​%E'' ​         | Same as ''​%e'',​ but with an upper-case ''​E''​ in the printed format ​                                                                                                                                                        ​+|''​%E''​|Same as ''​%e'',​ but with an upper-case ''​E''​ in the printed format| 
-| ''​%g'' ​         | Interprets the associated argument as **double**, but prints it like ''​%f''​ or ''​%e'' ​                                                                                                                                     +|''​%g''​|Interprets the associated argument as **double**, but prints it like ''​%f''​ or ''​%e''​| 
-| ''​%G'' ​         | Same as ''​%g'',​ but print it like ''​%E'' ​                                                                                                                                                                                  ​+|''​%G''​|Same as ''​%g'',​ but print it like ''​%E''​| 
-| ''​%c'' ​         | Interprets the associated argument as character: only the first character of a given argument is printed ​                                                                                                                  ​+|''​%c''​|Interprets the associated argument as **char**: only the first character of a given argument is printed| 
-| ''​%s'' ​         | Interprets the associated argument literally as string ​                                                                                                                ​+|''​%s''​|Interprets the associated argument literally as string| 
-| ''​%n'' ​         No conversion or printing is done. Assigns the number of so far printed characters ​to the variable named in the corresponding argument ​(similat ​to C'''​printf''​)                                                         +|''​%n''​|Assigns the number of characters printed ​so far to the variable named in the corresponding argument. Can't specify an array index. If the given name is already an array, the value is assigned ​to the zeroth element.| 
-| ''​%(FORMAT)T'' ​ | output the date-time string resulting from using ''​FORMAT''​ as a format string for ''​strftime(3)''​. The associated argument is the number of seconds since Epoch, or ''​-1''​ (current time) or ''​-2''​ (shell startup time)  +|''​%a''​|Interprets the associated argument as **double**, and prints it in the form of a C99 [[http://​www.exploringbinary.com/​hexadecimal-floating-point-constants/​ | hexadecimal floating-point literal]].| 
-| ''​%%'' ​         | No conversion is done. Produces a ''​%''​ (percent sign)                                                                                                                                                                     ​| +|''​%A''​|Same as ''​%a'',​ but print it like ''​%E''​| 
- +|''​%(FORMAT)T''​|output the date-time string resulting from using ''​FORMAT''​ as a format string for ''​strftime(3)''​. The associated argument is the number of seconds since Epoch, or ''​-1''​ (current time) or ''​-2''​ (shell startup time). If no corresponding argument is supplies, the current time is used as default
 +|''​%%''​|No conversion is done. Produces a ''​%''​ (percent sign)|
  
 Some of the mentioned format specifiers can modify their behaviour by getting a format modifier: Some of the mentioned format specifiers can modify their behaviour by getting a format modifier:
- 
 ==== Modifiers ==== ==== Modifiers ====
  
Line 129: Line 126:
 |''<​space>''​|Pad a positive number with a space, where a minus (''​-''​) is for negative numbers| |''<​space>''​|Pad a positive number with a space, where a minus (''​-''​) is for negative numbers|
 |''​+''​|Prints all numbers **signed** (''​+''​ for positive, ''​-''​ for negative)| |''​+''​|Prints all numbers **signed** (''​+''​ for positive, ''​-''​ for negative)|
 +|''<​nowiki>'</​nowiki>''​|For decimal conversions,​ the thousands grouping separator is applied to the integer portion of the output according to the current LC_NUMERIC|
  
 __**The "​alternative format"​ modifier ''#'':​**__ __**The "​alternative format"​ modifier ''#'':​**__
Line 147: Line 145:
  
 ==== Escape codes ==== ==== Escape codes ====
 +
 +These are interpreted if used anywhere in the format string, or in an argument corresponding to a ''​%b''​ format.
  
 ^Code^Description^ ^Code^Description^
Line 162: Line 162:
 |''​\0<​NNN>''​|same as ''​\<​NNN>''​| |''​\0<​NNN>''​|same as ''​\<​NNN>''​|
 |''​\x<​NNN>''​|Interprets ''<​NNN>''​ as **hexadecimal** number and prints the corresponding character from the character set (**3 digits**)| |''​\x<​NNN>''​|Interprets ''<​NNN>''​ as **hexadecimal** number and prints the corresponding character from the character set (**3 digits**)|
-|''​\u<​NNNN>''​|same as ''​\x<​NNN>'',​ but **4 digits** ​ +|''​\u<​NNNN>''​|same as ''​\x<​NNN>'',​ but **4 digits**| 
-|''​\U<​NNNNNNNN>''​|same as ''​\x<​NNN>'',​ but **8 digits** ​ |+|''​\U<​NNNNNNNN>''​|same as ''​\x<​NNN>'',​ but **8 digits**|
  
-===== Examples =====+The following additional escape and extra rules apply only to arguments associated with a ''​%b''​ format:
  
 +|''​\c''​|Terminate output similarly to the ''​\c''​ escape used by ''​echo -e''​. printf produces no additional output after coming across a ''​\c''​ escape in a ''​%b''​ argument.|
  
 +  * Backslashes in the escapes: ''​\<​nowiki>'</​nowiki>'',​ ''​\"'',​ and ''​\?''​ are not removed.
 +  * Octal escapes beginning with ''​\0''​ may contain up to four digits. (POSIX specifies up to three).
  
 +These are also respects in which ''​%b''​ differs from the escapes used by [[syntax/​quoting#​ansi_c_like_strings | $'​...'​]] style quoting.
 +
 +===== Examples =====
  
 ==== Snipplets ==== ==== Snipplets ====
 +
   * print the decimal representation of a hexadecimal number (preserve the sign)   * print the decimal representation of a hexadecimal number (preserve the sign)
     * ''​printf "​%d\n"​ 0x41''​     * ''​printf "​%d\n"​ 0x41''​
Line 199: Line 206:
 done done
 </​code>​ </​code>​
- 
  
 ==== Ensure well-formatted MAC address ==== ==== Ensure well-formatted MAC address ====
Line 214: Line 220:
 the_mac="​$(printf "​%02X:​%02X:​%02X:​%02X:​%02X:​%02X"​ 0x${the_mac//:/​ 0x})" the_mac="​$(printf "​%02X:​%02X:​%02X:​%02X:​%02X:​%02X"​ 0x${the_mac//:/​ 0x})"
 </​code>​ </​code>​
- 
  
 ==== Replacement echo ==== ==== Replacement echo ====
Line 237: Line 242:
 fi fi
 </​code>​ </​code>​
 +
 ==== prargs Implementation ==== ==== prargs Implementation ====
  
Line 271: Line 277:
 Please read the manpage of ''​strftime(3)''​ to get more information about the supported formats. Please read the manpage of ''​strftime(3)''​ to get more information about the supported formats.
  
 +===== differences from awk printf =====
  
-==== Using printf ​inside ​of awk ====+Awk also derives its //printf()// function from C, and therefore has similar format specifiers. ​ However, in all versions ​of awk the space character is used as a string concatenation operator, so it cannot be used as an argument separator. ​ **Arguments to awk printf must be separated by commas.** ​ Some versions of awk do not require printf arguments to be surrounded by parentheses,​ but you should use them anyway to provide portability.
  
-Here'​s ​the gotcha:+In the following example, the two strings are concatenated by the intervening space so that no argument remains to fill the format.
  
 <​code>​ <​code>​
- 
-$ printf "​%s\n"​ "​Foo"​ 
-Foo 
  
 $ echo "​Foo"​ | awk '{ printf "​%s\n"​ $1 }' $ echo "​Foo"​ | awk '{ printf "​%s\n"​ $1 }'
Line 289: Line 293:
 </​code>​ </​code>​
  
-One fix is to use commas to separate ​the format from the arguments:+Simply replacing ​the space with a comma and adding parentheses yields correct awk syntax.
  
 <​code>​ <​code>​
-$ echo "​Foo"​ | awk '{ printf "​%s\n",​ $1 }'+$ echo "​Foo"​ | awk '{ printf"​%s\n",​ $1 }'
 Foo Foo
 </​code>​ </​code>​
  
-Or, use **printf** ​the way that awk wants you to:+With appropriate metacharacter escaping ​the bash printf can be called from inside ​awk (as from perl and other languages that support shell callout) as long as you don't care about program efficiency or readability.
  
 <​code>​ <​code>​
-echo "​Foo"​ | awk '{ printf $1 "\n" }'+echo "​Foo"​ | awk '​{ ​system( "printf ​\"​%s\\n \" \"" ​$1 "​\"​" ​ ) }'
 Foo Foo
 </​code>​ </​code>​
  
-But then you lose the ability to pad numbersset field widthsetcthat **printf** has.+===== Differences from C, and portability considerations ===== 
 + 
 +  * The a, A, e, E, f, F, g, and G conversions are supported by Bash, but not required by POSIX. 
 + 
 +  * There is no wide-character support (wprintf). For instance, if you use ''​%c'', ​you're actually asking for the first byte of the argument. Likewisethe maximum ​field width modifier (dot) in combination with ''​%s''​ goes by bytesnot charactersThis limits some of printf'​s functionality to working with ascii only. ksh93'​s ''​printf''​ supports the ''​L''​ modifier with ''​%s''​ and ''​%c''​ (but so far not ''​%S''​ or ''​%C''​) in order to treat precision as character width, not byte count. zsh appears to adjust itself dynamically based upon ''​LANG''​ and ''​LC_CTYPE''​. If ''​LC_CTYPE=C'',​ zsh will throw "​character not in range" errors, and otherwise supports wide characters automatically if a variable-width encoding is set for the current locale. 
 + 
 +  ​Bash recognizes and skips over any characters present in the length modifiers specified by POSIX during format string parsing. 
 +<code c|builtins/​printf.def>​ 
 +#define LENMODS "​hjlLtz"​ 
 +... 
 +/skip possible format modifiers */ 
 +modstart = fmt; 
 +while (*fmt && strchr (LENMODS, *fmt)) 
 +fmt++; 
 +</​code>​ 
 + 
 +  * mksh has no built-in ​printf ​by default (usually). There is an unsupported compile-time option to include a very poor, basically unusable implementation. For the most part you must rely upon the system'​s ''/​usr/​bin/​printf''​ or equivalent. The mksh maintainer recommends using ''​print''​. The development version (post- R40f) adds a new parameter expansion in the form of ''​${name@Q}''​ which fills the role of ''​printf %q''​ -- expanding in a shell-escaped format. 
 + 
 +  ​ksh93 optimizes builtins run from within a command substitution and which have no redirections to run in the shell'​s process. Therefore the ''​printf -v''​ functionality can be closely matched by ''​var=$(printf ...)''​ without a big performance hit. 
 +<​code>​ 
 +# Illustrates Bash-like behavior. Redefining printf is usually unnecessary / not recommended. 
 +function printf { 
 +    case $1 in 
 +        -v) 
 +            shift 
 +            nameref x=$1 
 +            shift 
 +            x=$(command printf "​$@"​) 
 +            ;; 
 +        ​*
 +            command printf "​$@"​ 
 +    esac 
 +
 +builtin cut 
 +print $$ 
 +printf -v '​foo[2]'​ '​%d\n'​ "$(cut -d ' ' -f 1 /​proc/​self/​stat)"​ 
 +typeset -p foo 
 +# 22461 
 +# typeset -a foo=([2]=22461) 
 +</​code>​ 
 + 
 +  * The optional Bash loadable ''​print''​ may be useful for ksh compatibility and to overcome some of [[commands/​builtin/​echo | echo]]'​s portability pitfalls. Bash, ksh93, and zsh's ''​print''​ have an ''​-f''​ option which takes a ''​printf''​ format string and applies it to the remaining arguments. Bash lists the synopsis as: ''​print:​ print [-Rnprs] [-u unit] [-f format] [arguments]''​. However, only ''​-Rrnfu''​ are actually functional. Internally, ''​-p''​ is a noop (it doesn'​t tie in with Bash coprocs at all), and ''​-s''​ only sets a flag but has no effect. ''​-Cev''​ are unimplemented. 
 + 
 +  * Assigning to variables: The ''​printf -v''​ way is slightly different to the way using command-substitution. [[syntax:​expansion:​cmdsubst | Command substitution]] removes trailing newlines before substituting the text, ''​printf -v''​ preserves all output. 
 ===== See also ===== ===== See also =====
  
-  * Internal: [[snipplets:​print_horizontal_line|Code snip: Print a horizontal line]] uses some ''​printf''​ examples +  * SUS[[http://​pubs.opengroup.org/​onlinepubs/​9699919799/​utilities/​printf.html | printf utility]] and [[http://​pubs.opengroup.org/​onlinepubs/​9699919799/​functions/​printf.html | printf() function]] 
-  * External: ​[[BashFAQ>​018 | Greg's BashFAQ 18: How can I use numbers with leading zeros in a loop, e.g., 01, 02?]]+  * [[snipplets:​print_horizontal_line|Code snip: Print a horizontal line]] uses some ''​printf''​ examples 
 +  * [[BashFAQ>​018 | Greg's BashFAQ 18: How can I use numbers with leading zeros in a loop, e.g., 01, 02?]]
  • commands/builtin/printf.1330301249.txt
  • Last modified: 2012/02/27 00:07
  • by pi3832