如何为 printf 动态创建格式化规则?

How to dynamically create formatting rules for printf?

我正在尝试在 30 个字符宽度的多列中打印几行:

#!/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

虽然 运行 我希望它输出:

a              b              c              d

但它输出:

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

如何使用我为 printf 动态构建的格式化规则?

在格式字符串中使用单个“%”字符。你已经逃脱了他们,所以没有任何东西被取代。

您对自己的数据有多信任?您可以让命令解析器去除额外的空格,但要冒一定的风险。

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

如果您的数据在文件中...

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

甚至

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

你可能看不到的是,换行符也被打印在一个15宽的字段中,所以行尾有很多空格。

注意这些重用了单一格式字符串(这很简单我没有引用,但你通常应该引用)。

在这里将引号放在错误的地方会导致问题...

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

你会从

得到相同的结果
$: printf %-15s "$full_string" $'\n'

通常,您想要 引号,但可以通过创造性地省略它们并让解析器处理空白来完成有用的事情。请注意您得到的是什么。如果其中一个字段中有嵌入的空格,则所有投注均无效。

许多相同的注意事项也适用于格式本身。

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

因此您可以根据需要动态创建不同的格式,只需将变量用双引号引起来就可以对其进行解析 "correctly"。一如既往,测试一下。