简体   繁体   中英

How to dynamically create formatting rules for printf?

I am trying to print several lines in multiple columns of 30 characters width:

#!/bin/bash
chars_width=15
full_string="a\\nb\\nc\\nd"
number_of_columns=$(( $(tput cols) / $chars_width ))

for ((i = 0; i < number_of_columns; i++)); do
    formatting_string="$formatting_string%%-"$chars_width"s "
done

echo "$full_string" | xargs -L $number_of_columns | \
    while read -r values
    do
        printf "$formatting_string\\n" $values
    done
exit

While running this I would expect it to output:

a              b              c              d

But it outputs:

%-15s %-15s %-15s %-15s

How to put my dynamically built formatting rules for printf to use?

Use single '%' chars in your format string. You've escaped them, so nothing gets substituted.

How much do you trust your data? You might let the command parser strip extra whitespace, at the price of some risk.

$: full_string=$'a\nb\nc\nd'
$: printf %-15s $full_string $'\n'
a              b              c              d

If your data is in a file...

$: r=( $(<file) )
$: printf %-15s "${r[@]}" $'\n'
a              b              c              d

or even

$: printf %-15s $(<file) $'\n'
a              b              c              d

What you may not see is that the newline was also printed in a 15-wide field, so there are a lot of spaces at the end of the line.

Note these reuse the single formatting string (which was simple enough I didn't quote, but you usually should).

Putting quotes in the wrong places here would cause problems...

$:  printf %-15s "$(<file)" $'\n'
a
b
c
d

You'd get the same result from

$: printf %-15s "$full_string" $'\n'

Generally, you want quotes, but useful things can be done by creatively leaving them out and letting the parser manipulate the whitespace. Just be aware of what you are getting. if there's embedded whitespace in one of those fields, all bets are off.

Much the same set of caveats applies to the format itself.

$: f="%-15s %5s"
$: printf $f $x $'\n' # oops!
%5s            a              b              c              d
$: printf "$f" $x $'\n'
a                   bc                   d

So you can dynamically create differing formats if you want, and just quote the variable in double-quotes to have it parsed "correctly". As always, test it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM