【问题标题】:Using variables in printf format使用 printf 格式的变量
【发布时间】:2014-08-20 14:37:04
【问题描述】:

假设我有一个这样的文件:

$ cat a
hello this is a sentence
and this is another one

我想打印前两列并在它们之间添加一些填充。由于此填充可能会发生变化,因此我可以使用 7:

$ awk '{printf "%7-s%s\n", $1, $2}' a
hello  this
and    this

17:

$ awk '{printf "%17-s%s\n", $1, $2}' a
hello            this
and              this

或者25,或者......你明白了:数字可能会有所不同。

然后出现了一个问题:是否可以为这个N 分配一个变量,而不是硬编码%N-s 格式的整数?

我尝试了这些事情但没有成功:

$ awk '{n=7; printf "%{n}-s%s\n", $1, $2}' a
%{n}-shello
%{n}-sand

$ awk '{n=7; printf "%n-s%s\n", $1, $2}' a
%n-shello
%n-sand

理想情况下,我想知道是否可以这样做。如果不是,最好的解决方法是什么?

【问题讨论】:

  • 哦! fedorqui 问了一个问题!

标签: printf awk


【解决方案1】:

如果您在格式字符串中使用*,它会从参数中获取一个数字

awk '{printf "%*-s%s\n", 17, $1, $2}' file
hello            this
and              this

awk '{printf "%*-s%s\n", 7, $1, $2}' file
hello  this
and    this

如阅读The GNU Awk User’s Guide #5.5.3 Modifiers for printf Formats:

C 库 printf 的动态宽度和精确度能力(例如, 支持“%*.*s”)。而不是提供明确的宽度和/或 prec 格式字符串中的值,它们在参数列表中传递。为了 示例:

w = 5
p = 3
s = "abcdefg"
printf "%*.*s\n", w, p, s

完全等同于:

s = "abcdefg"
printf "%5.3s\n", s

【讨论】:

  • 太棒了,是的!你有任何解释这种行为的来源吗?
  • 不知道这个。 +1 伙计
  • @fedorqui 当然,据说here
  • 这些和位置说明符是我最喜欢的未充分使用(和支持不足)的说明符。
  • 我所能做的就是坐下来点击 +1 ... :-)。你知道我希望做的功能不存在 - 能够在填充时指定任何前导字符。就像你可以用 awk 'BEGIN{printf "%05d\n",17}' 用零填充左边一样,如果你可以用awk 'BEGIN{printf "%#5d\n",17}'#s 或任何其他字符填充通常会很方便。这样,如果您想要一串 5 个#s,您可以简单地使用awk 'BEGIN{printf "%#5d\n",""}' 而不是awk 'BEGIN{print gensub(/0/,"#","g",sprintf("%05d",""))}' 或类似的。哦,好吧,我们将再次走向语言膨胀..
【解决方案2】:

这算不算?

想法是构建“动态”fmt,用于printf

kent$   awk '{n=7;fmt="%"n"-s%s\n"; printf fmt, $1, $2}' f 
hello  this
and    this

【讨论】:

  • 好主意!非常类似于 konsolebox,只是你使用“模型-视图-控制器”模式:)
  • 我的首选解决方案是答案。示例:git log --pretty=%ae | awk '{ n=length($1) ; if (n>l) l=n ; arr[tolower($1)]++ } END { fmt="%-"l"s: %4i\n" ; for (i in arr) printf(fmt, i, arr[i]) | "sort" }' - 意思是计算 git 作者在 END 块 printf 中使用的最大长度。
【解决方案3】:

使用简单的字符串连接。

这里"%"n"-s%s\n" 连接为格式的单个字符串。根据以下示例,生成的格式字符串为%7-s%s\n

awk -v n=7 '{ printf "%" n "-s%s\n", $1, $2}' file
awk '{ n = 7; printf "%" n "-s%s\n", $1, $2}' file

输出:

hello  this
and    this

【讨论】:

  • 不错!这似乎成功了。您介意为未来的读者添加一些解释吗?
  • 非常感谢,如果没有出现 jaypal 的答案,我会选择这个答案。清晰且解释清楚,谢谢!
【解决方案4】:

你可以使用 eval (也许不是所有转义字符最漂亮的,但它有效)

i=15
eval "awk '{printf \"%$i-s%s\\n\", \$1, \$2}' a"

输出:

hello          this
and            this

【讨论】:

  • 是的,很好,虽然我一直在寻找“完全 awk 特定”的东西。
  • 至少它对于你想做类似事情的其他命令是通用的......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-30
  • 2019-10-28
  • 1970-01-01
  • 2015-12-15
相关资源
最近更新 更多