如何使用 awk printf 命令正确格式化输出?

如何使用 awk printf 命令正确格式化输出?

我有以下文件:

echo filename
    dfT08r352|30.5|2010/06/01|2016/08/29|2281|6.24503764544832|74.9404517453799|
    zm00dr121|37|2008/03/05|2011/09/12|1285.95833333333|3.52076203513575|42.249144421629|
    ccvd00121|41.6|2008/03/05|2012/03/05|1461|4|48|
    sddf00121|39.6|2008/03/05|2012/09/10|1649.95833333333|4.51733972165184|54.208076659822|
    fttt00121|41|2008/03/05|2013/09/16|2020.95833333333|5.53308236367785|66.3969883641342|
    ghhyy0121|42.2|2008/03/05|2014/03/18|2203.95833333333|6.03410905772302|72.4093086926762|

我正在尝试使用 awk printf 格式化此文件以具有以下所需的格式:

  1. 保持相同的字段顺序(左-->右)
  2. 有逗号“,”FS
  3. 只为l三个字段($5、$6、$7)所有数字均为 4 位数字,如果少于 4 位数字,则有一个前导零,并且点后只有 2 位数字,如 0123.12 或 1234.10

我写了以下 awk 命令

awk -F"|" '{print $1","$2","$3","$4}{format = "%04.2f,%04.2f,%04.2f,"}{printf format, $5,$6,$7}' filename

但是以下输出存在以下问题:

  1. 不按顺序(左-->右)

  2. 没有前导零

    dfT08r352,30.5,2010/06/01,2016/08/29
    2281.00,6.25,74.94,zm00dr121,37,2008/03/05,2011/09/12
    1285.96,3.52,42.25,ccvd00121,41.6,2008/03/05,2012/03/05
    1461.00,4.00,48.00,sddf00121,39.6,2008/03/05,2012/09/10
    1649.96,4.52,54.21,fttt00121,41,2008/03/05,2013/09/16
    2020.96,5.53,66.40,ghhyy0121,42.2,2008/03/05,2014/03/18
    

有人可以让我知道我的错误是什么以及如何解决吗?

答案1

您的字段顺序正确,但您的第一个打印语句添加了换行符(输出记录分隔符),因此您的数据在那里,但只是意外换行。

第二个问题是你告诉 printf 使用宽度 4;包括小数点及其后面的两位数字,只留下一位作为前导数字,不留任何填充。尝试使用 5 作为宽度,以便将数据填充到总共四个数字。如果你想要4位数字小数点,然后将宽度更改为 7。

这是我对你的程序进行的最短的更改,以输出我认为你想要的内容:

awk -F"|" '{
  format = "%05.2f,%05.2f,%05.2f"; 
  print $1","$2","$3","$4"," sprintf(format, $5,$6,$7)}' filename

我将多个{ }块合并为一个,并将打印语句合并为一个。

如果我从头开始编写 awk 语句,我可能会这样做:

awk -v FS=\| -v OFS=, '{
  $5=sprintf("%05.2f", $5); 
  $6=sprintf("%05.2f", $6); 
  $7=sprintf("%05.2f", $7); 
  print $1,$2,$3,$4,$5,$6,$7}' filename

它显式设置输入字段分隔符、输出字段分隔符,显式地自行转换每个字段,然后打印所需的字段,并使用 OFS 分隔它们。

答案2

一种方法是:

awk -F \| -v OFS=, '{ NF--; for(i = NF-2; i <= NF; i++) $i = sprintf("%07.2f", $i) } 1' filename

相关内容