Bash awk输出列宽度为固定

Bash awk输出列宽度为固定,bash,shell,awk,Bash,Shell,Awk,我想打印一个“echo”命令输出,该命令输出的字段由“|”分隔成列,所有列的宽度固定不变。列数可能会有所不同,因此,宽度应为适用于所有列的全局设置 样本输入 1234|sdan:active:running|sdax:active:running|sdbh:active:running|sdcv:active:running|sddf:active:running|sddp:active:running|Total paths 6 : OK 1235|sdc:active:running|sdm

我想打印一个“echo”命令输出,该命令输出的字段由“|”分隔成列,所有列的宽度固定不变。列数可能会有所不同,因此,宽度应为适用于所有列的全局设置

样本输入

1234|sdan:active:running|sdax:active:running|sdbh:active:running|sdcv:active:running|sddf:active:running|sddp:active:running|Total paths 6 : OK
1235|sdc:active:running|sdm:active:running|sdw:active:running|sdbk:active:running|sdbu:active:running|sdce:active:running|Total paths 6 : OK
1236|sdam:active:running|sdaw:active:running|sdbg:active:running|sdde:active:running|sdcu:active:running|sddo:active:running|Total paths 6 : OK
你需要awk吗

cat input.txt | tr '|' ' ' | rev | column -t | rev
如果您真的愿意,可以用awk替换tr,但是制表的神奇之处在于rev和column-t


只需修改每行上的每个字段,就可以轻松做到这一点。以下文字记录显示了如何做到这一点:

pax> cat qq.awk
BEGIN { OFS = FS = "|" }
{   for (i = 1; i <= NF; i++) {
        $i = sprintf("%-12s", $i)
    }
    print
}

pax> cat qq.input
1234|sdan:active|sdcv:running|sddf:dead|sddp:active|3 paths:BAD
1235|sdc:active|sdm:active|sdw:running|sdbk:running|4 paths:OK
1236|sda:active|sdm:dead|2 paths:BAD

pax> awk -f qq.awk qq.input
1234        |sdan:active |sdcv:running|sddf:dead   |sddp:active |3 paths:BAD
1235        |sdc:active  |sdm:active  |sdw:running |sdbk:running|4 paths:OK
1236        |sda:active  |sdm:dead    |2 paths:BAD
这将用该字段空间的内容替换每个字段,该字段空间的内容至少填充到指定的宽度

如果希望使用一行程序而不是格式良好的脚本,可以使用:

awk 'BEGIN{OFS=FS="|"}{for(i=1;i<=NF;i++){$i=sprintf("%-12s",$i)};print}' qq.input
awk更容易,但可以通过sed实现:

鉴于:

以下是一个awk,它将打印所有字段,以w值或该字段中字符串长度中的较长者为准:

$ awk 'BEGIN{OFS=FS="|"; w=8}
 {for (i=1;i<=NF;i++) printf "%-*s%s", w, $i, i==NF ? ORS : OFS}' file
1234    |sdan:active|sdax:active|sdbh:active|sdcv:active|sddf:active|sddp:active|Total paths 6 : OK
1235    |sdc:active|sdm:active|sdw:active|sdbk:active|sdbu:active|sdce:active|Total paths 6 : OK
1236    |sdam:active|sdaw:active|sdbg:active|sdde:active|sdcu:active|sddo:active|Total paths 6 : OK
如果要剪切较长的字段以适应固定宽度,请执行以下操作:

$ awk 'BEGIN{OFS=FS="|"; w=11}
     {for (i=1;i<=NF;i++) printf "%-*s%s", w, substr($i,1,w), i==NF ? ORS : OFS}
     ' file
1234       |sdan:active|sdax:active|sdbh:active|sdcv:active|sddf:active|sddp:active|Total paths
1235       |sdc:active |sdm:active |sdw:active |sdbk:active|sdbu:active|sdce:active|Total paths
1236       |sdam:active|sdaw:active|sdbg:active|sdde:active|sdcu:active|sddo:active|Total paths
$ awk 'BEGIN{OFS=FS="|"}
       NR==FNR {for (i=1;i<=NF;i++) w=length($i)+1>w ? length($i)+1 : w; next}
               {for (i=1;i<=NF;i++) printf "%-*s%s", w, $i, i==NF ? ORS : OFS}
     ' file file
1234               |sdan:active        |sdax:active        |sdbh:active        |sdcv:active        |sddf:active        |sddp:active        |Total paths 6 : OK 
1235               |sdc:active         |sdm:active         |sdw:active         |sdbk:active        |sdbu:active        |sdce:active        |Total paths 6 : OK 
1236               |sdam:active        |sdaw:active        |sdbg:active        |sdde:active        |sdcu:active        |sddo:active        |Total paths 6 : OK 
如果要遍历文件以获得适合所有字段的宽度,请使用该宽度以固定宽度打印所有字段:

$ awk 'BEGIN{OFS=FS="|"; w=11}
     {for (i=1;i<=NF;i++) printf "%-*s%s", w, substr($i,1,w), i==NF ? ORS : OFS}
     ' file
1234       |sdan:active|sdax:active|sdbh:active|sdcv:active|sddf:active|sddp:active|Total paths
1235       |sdc:active |sdm:active |sdw:active |sdbk:active|sdbu:active|sdce:active|Total paths
1236       |sdam:active|sdaw:active|sdbg:active|sdde:active|sdcu:active|sddo:active|Total paths
$ awk 'BEGIN{OFS=FS="|"}
       NR==FNR {for (i=1;i<=NF;i++) w=length($i)+1>w ? length($i)+1 : w; next}
               {for (i=1;i<=NF;i++) printf "%-*s%s", w, $i, i==NF ? ORS : OFS}
     ' file file
1234               |sdan:active        |sdax:active        |sdbh:active        |sdcv:active        |sddf:active        |sddp:active        |Total paths 6 : OK 
1235               |sdc:active         |sdm:active         |sdw:active         |sdbk:active        |sdbu:active        |sdce:active        |Total paths 6 : OK 
1236               |sdam:active        |sdaw:active        |sdbg:active        |sdde:active        |sdcu:active        |sddo:active        |Total paths 6 : OK 
您可以使用如下所示的列:

$column-s'|'-o'|'-t input.txt 1234 | sdan:active:running | sdax:active:running | sdbh:active:running | sdcv:active:running | sddf:active:running | sddp:active:running |总路径6:OK 1235 | sdc:活动:运行| sdm:活动:运行| sdw:活动:运行| sdbk:活动:运行| sdbu:活动:运行| sdce:活动:运行|总路径6:正常 1236 | sdam:active:running | sdaw:active:running | sdbg:active:running | sdde:active:running | sdcu:active:running | sddo:active:running |总路径6:OK
看,然后再试一次。这里的rev的目的是什么?当省略它们时,我看不到任何区别。diito用于cat和第一个管道vs<。此外,column只创建足够宽的列来容纳每个字段,它不会使所有列的宽度都与OP要求的相同。column-t只是清理了我一直在挣扎的混乱。我很高兴你回答了这个问题,尽管投了反对票,但没有删除你的答案;我@Ed,说得好,我会解决的。我倾向于使用分号,因为我经常将答案中的代码格式化为可读的,然后将其全部放在一行,以便实际完成工作。
$ awk 'BEGIN{OFS=FS="|"}
       NR==FNR {for (i=1;i<=NF;i++) w=length($i)+1>w ? length($i)+1 : w; next}
               {for (i=1;i<=NF;i++) printf "%-*s%s", w, $i, i==NF ? ORS : OFS}
     ' file file
1234               |sdan:active        |sdax:active        |sdbh:active        |sdcv:active        |sddf:active        |sddp:active        |Total paths 6 : OK 
1235               |sdc:active         |sdm:active         |sdw:active         |sdbk:active        |sdbu:active        |sdce:active        |Total paths 6 : OK 
1236               |sdam:active        |sdaw:active        |sdbg:active        |sdde:active        |sdcu:active        |sddo:active        |Total paths 6 : OK