Bash Awk+;printf:用“替换长值”#######&引用;

Bash Awk+;printf:用“替换长值”#######&引用;,bash,awk,printf,Bash,Awk,Printf,我从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,

我从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,我可以用字符串########替换长值,但当awk+printf将此字段作为十进制数字读取时,它显示0.00%,而不是所需的######。 有没有办法写“如果这个变量太长,就打印出来”呢? 谢谢

吉咪

编辑:

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

我的输出:

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
我的愿望(或类似愿望):


让我们从使用合理的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”
开始{split(fmt,fmtA,//)}
{
对于(i=1;i=6){
$i=“#######”
}
}
打印
}
“/home/jm/mysql/pruebas/pruebat.txt>>/home/jm/mysql/pruebas/prn.tx

让我们从用合理的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”
开始{split(fmt,fmtA,//)}
{
对于(i=1;i=6){
$i=“#######”
}
}
打印
}
“/home/jm/mysql/pruebas/pruebat.txt>>/home/jm/mysql/pruebas/prn.tx

请发布一个输入和输出示例,说明您需要什么;另外,试着重新表述你的问题——主要是你的代码——甚至很难写下你想要的东西,发布一个输入和输出的例子;另外,试着重新表述你的问题——主要是你的代码——甚至很难缩进。我的调试:awk:cmd。第5行:(FILENAME=/home/jm/mysql/pruebas/pruebatt.txt FNR=1)致命:参数不足,无法满足格式字符串“%-7s%-30s%'10d%'10d%'8.2f%'8.2f%'8.2f'^。我现在已经更新了脚本。我还从您发布的预期输出中看到,您只想在长度考虑中计算非空格,因此我更新了脚本以反映这一点。我实际上认为这是一种错误的方法——最好是按照你的需要得到你的数字,然后在后面加上空格,但因为格式信息隐藏在你的$A中,等等。我不知道它到底需要如何编码。您真的需要将格式信息放在shell变量中吗?还是可以用awk来完成?字母A到F只是假装设置每个字段的长度(实际上是7,30,10,10,8)。这样做的原因是避免在我为页眉运行的第一个awk(因为字段的格式不同,文本而不是数字)和为页脚运行的第二个awk(未在附加的脚本中显示,以避免冗余)中设置它。如您所见,文本(s)、数字(d)和浮点(f)格式已经写入awk语句中。谢谢。请再说一遍:正如您所料,您的脚本工作得很好,但是,对于固定长度超过6位的列,不需要(也不希望)将它们转换为“####”。相反,第二列的长度实际上是30位,因此不应进行转换。也许“我们”走的路不对……;)谢谢Ed。我的调试:awk:cmd。第5行:(FILENAME=/home/jm/mysql/pruebas/pruebatt.txt FNR=1)致命:参数不足,无法满足格式字符串“%-7s%-30s%'10d%'10d%'8.2f%'8.2f%'8.2f'^。我现在已经更新了脚本。我还从您发布的预期输出中看到,您只想在长度考虑中计算非空格,因此我更新了脚本以反映这一点。我实际上认为这是一种错误的方法——最好是按照你的需要得到你的数字,然后在后面加上空格,但因为格式信息隐藏在你的$A中,等等。我不知道它到底需要如何编码。您真的需要将格式信息放在shell变量中吗?还是可以用awk来完成?字母A到F只是假装设置每个字段的长度(实际上是7,30,10,10,8)。这样做的原因是避免在我为页眉运行的第一个awk(因为字段的格式不同,文本而不是数字)和为页脚运行的第二个awk(未在附加的脚本中显示,以避免冗余)中设置它。如您所见,文本(s)、数字(d)和浮点(f)格式已经写入awk语句中。谢谢。请再说一遍:正如您所料,您的脚本工作得很好,但是,对于固定长度超过6位的列,不需要(也不希望)将它们转换为“####”。相反,第二列的长度实际上是30位,因此不应进行转换。也许“我们”走的路不对……;)
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
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