【问题标题】:Awk + printf: substitute long values by "#######"awk + ​​printf:用“#######”替换长值
【发布时间】:2012-12-30 19:32:38
【问题描述】:

我从 mysql 中的查询中获取了一些数据,我需要将其转换为漂亮的表格。 然后我使用 awk 和 printf 来对齐列、格式化数字等。

cat /home/jm/mysql/pruebas/pruebat.txt | awk 'BEGIN { FS = ";" } ; {printf "%-'$A's %-'$B's %'\'''$C'd %'\'''$D'd %'\'''$E'd %'\'''$F'.2f %'\'''$F'.2f %'\'''$F'.2f\n", $1, $2, $3, $4, $5, $6, $7, $8 }' >> /home/jm/mysql/pruebas/prn.tx

当某些字段太长时会出现我的问题(例如,太岁之间的百分比变化是 -12.345,67%)。在这种情况下,我宁愿只显示######。 如果我在查询中使用 case/when/then/end,我可以用字符串 ###### 替换 long 值,但是当 awk+printf 将此字段读取为十进制数时,它会显示 0.00% 而不是所需 ######。 有没有办法写“如果这个变量太长,只打印######”? 谢谢,

jm

编辑:

我的源文件(忘记标题):

S_V;NO INVENTARIABLES;-41.7000;-67.5200;-25.8200;61.91846523;100.00000000;100.00000000
S_A;ARTICULOS PROMOCIONES;54.4400;631.3200;576.8800;1059.66201323;-1412.30712711;-19.76018501
S_B;PRODUCTOS TECNICOS;975.6000;1951.2000;975.6000;100.00000000;36.01476015;34.61254613
S_S;MATERIAL ELECTRICO;2237.6600;5103.2500;2865.5900;128.06190395;40.21030898;43.42859942

我的输出:

fam     nombre                               2011       2012        var        %   %mgn11   %mgn12
--------------------------------------------------------------------------------------------------
S_V     NO INVENTARIABLES                     -41        -67        -25    61.92   100.00   100.00
S_A     ARTICULOS PROMOCIONES                  54        631        576 1,059.66 -1,412.31   -19.76
S_B     PRODUCTOS TECNICOS                    975      1,951        975   100.00    36.01    34.61
S_S     MATERIAL ELECTRICO                  2,237      5,103      2,865   128.06    40.21    43.43

我的愿望(或类似的):

fam     nombre                               2011       2012        var        %   %mgn11   %mgn12
--------------------------------------------------------------------------------------------------
S_V     NO INVENTARIABLES                     -41        -67        -25    61.92   100.00   100.00
S_A     ARTICULOS PROMOCIONES                  54        631        576   ######   ######   -19.76
S_B     PRODUCTOS TECNICOS                    975      1,951        975   100.00    36.01    34.61
S_S     MATERIAL ELECTRICO                  2,237      5,103      2,865   128.06    40.21    43.43

【问题讨论】:

  • 请张贴输入和输出示例,说明您将拥有什么;并且,尝试改写你的问题——主要是你的代码——,甚至很难缩进

标签: bash awk printf


【解决方案1】:

让我们从用合理的 shell+awk 语法重写你的脚本开始吧,我能说的最好:

awk -F\; -v fmt="%-${A}s %-${B}s %'${C}d %'${D}d %'${E}d %'${F}.2f %'${F}.2f %'${F}.2f\n" '
{ printf fmt, $1, $2, $3, $4, $5, $6, $7, $8 }
' /home/jm/mysql/pruebas/pruebat.txt >> /home/jm/mysql/pruebas/prn.tx

现在,您遇到的问题是,您的格式字符串专门说要打印一个数字,而实际上您想打印一个字符串,因此请使用 sprintf 创建您的数字,然后如果您对结果更改不满意将其转换为字符串以供输出。像这样的东西(未经测试):

awk -F\; -v fmt="%-${A}s %-${B}s %'${C}d %'${D}d %'${E}d %'${F}.2f %'${F}.2f %'${F}.2f\n" '
BEGIN{ split(fmt,fmtA,/ /) }
{
    for (i=1;i<=NF;i++) {
       $i = sprintf(fmtA[i],$i)
       if (gsub(/[^[:space:]]/,"&",$i) > 6) {
           $i = "######"
       }
    }
    print
}
' /home/jm/mysql/pruebas/pruebat.txt >> /home/jm/mysql/pruebas/prn.tx

【讨论】:

  • 谢谢埃德。我的调试:awk:cmd。 line:5: (FILENAME=/home/jm/mysql/pruebas/pruebatt.txt FNR=1) 致命:没有足够的参数来满足格式字符串 `%-7s %-30s %'10d %'10d %'10d %' 8.2f %'8.2f %'8.2f' ^ 用完了这个
  • split() 由于您使用非默认 FS 而失败。我现在已经更新了脚本。
  • 我还从您发布的预期输出中看到,您只想在长度考虑中计算非空格,因此我更新了我的脚本以反映这一点。我实际上认为这是错误的方法 - 最好按照你想要的方式获取你的数字,然后用空格填充,但由于格式信息隐藏在你的 $A 等中。我不知道它是怎么做到的确实需要编码。您真的需要将格式信息放在 shell 变量中还是可以在 awk 中完成?
  • 字母 A 到 F 只是假装设置每个字段的长度(实际上是 7,30,10,10,10,8)。这样做的原因是避免在我为页眉运行的第一个 awk 中设置它(因为字段的格式不同,文本而不是数字)和我为页脚运行的第二个 awk(未在附加脚本中显示是多余的)。如您所见,文本(s),数字(d)和浮点(f)格式已经写在awk语句中。谢谢。
  • 再次返回:如您所料,您的脚本运行良好,但是对于那些固定长度超过 6 位的列,不需要(也不希望)将它们转换为“#### ###”。相反,第二列实际上是 30 位长,因此不应转换。也许“我们”没有走对路……;)
猜你喜欢
  • 2012-04-02
  • 1970-01-01
  • 2016-10-29
  • 1970-01-01
  • 1970-01-01
  • 2015-01-07
  • 2016-07-19
  • 2013-05-30
  • 2014-03-05
相关资源
最近更新 更多