8

I am experimenting with printf formatting in bash and I ran across this piece of code:

#/bin/bash
divider===============================
divider=$divider$divider

header="\n %-15s %8s %10s %11s\n"
format=" %-15s %08d %10s %11.2f\n"
width=55

printf "$header" "ITEM NAME" "ITEM ID" "COLOR" "PRICE"

printf "%$width.${width}s\n" "$divider"

printf "$format" \
Triangle 13  red 20 \
Oval 204449 "dark blue" 65.656 \
Square 3145 orange .7

The line that I am interested in is the line that says:

printf "%$width.${width}s\n" "$divider"

What is that variable reference doing? What does it mean?

1 Answer 1

10

The code "%$width.${width}s\n" generates a format string that is suitable for consumption by printf

In the script that you posted, width has been assigned the value 55, so that both $width and ${width} are expanded by bash to 55: the entire first parameter to printf expands to %55.55s\n; this is the format %s, with a field width and precision specifiers that ask to print on exactly 55 characters. Given the value of variable divider at this point, this will simply print a line of 55 equal signs. A perhaps simpler way of printing the same thing would have been perl -e 'print "=" x 55, "\n"'.

The simplest form for the field width specifier is an integer: this asks printf to use at least this many characters for printing. If the corresponding parameter requires fewer characters than this to print, then the output is left-padded with spaces.

The simplest form for the precision specifier is a dot followed by an integer: when applied to %s, this sets the maximum number of characters to print. (It has a different meaning for numeric types.)

In response to a comment, I will also mention a little bit about shell variable expansion (the complete explanation can be found by searching for "parameter expansion" in the bash documentation, see also $VAR vs ${VAR} and to quote or not to quote):

  • When a variable, say x, has been set, then $x expands to the value of x. If that value contains whitespace, then the expansion will be several words. This is why it's important in the code above that, for example, "$format" is within double quotes: this forces the expansion to be a single word (otherwise, printf would see a first parameter %-15s, followed by an argument %8s, etc., instead of receiving the entire format string as a single parameter).

  • It is permissible to write ${x} instead of just $x to expand the variable x; in the case above, "${width}s", it is necessary to do so because if one had written "$widths", then bash would try to get the value of variable widths, which is unset, resulting in an empty expansion.

4
  • Thank you for the quick response. What I am understanding is this: printf "%55s and printf "%${width}" is the same thing correct? Using "%$width.${width}s tells printf to format the string with 50 chars padding and limit to 50 chars. Is that correct?
    – Allan
    Commented Mar 24, 2015 at 2:10
  • also what I am having a hard time with is the use of brackets with the variable. printf ""%$widths" generates an error but printf "%${width}" does not. But somehow printf "%$width.${width}s\n" works. Can you tell me why or direct me to something that explains this? I don't know the terminology to search for.
    – Allan
    Commented Mar 24, 2015 at 2:18
  • To respond to your first comment, "%${width}s" expands to "%55s". The format "%50.50s" would ask to pad to 50 characters and to print no more than 50 characters, so you are entirely correct on that part. To respond to your second comment, $width vs ${width} is a matter of bash variable expansion; I will amend my answer to talk about it.
    – dhag
    Commented Mar 24, 2015 at 2:55
  • I see it now and thank you for the terminology. It helps when you have an idea of what to ask Google to get the relevant results.
    – Allan
    Commented Mar 24, 2015 at 3:41

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .