5

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?

8

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.

  • 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 Mar 24 '15 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 Mar 24 '15 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 Mar 24 '15 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 Mar 24 '15 at 3:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.