使用awk修改具有可变字段数的文件中第一列的宽度


10

我知道如何使用awk的printf函数,但是我不想指定每个字段。

例如,假设这是我的文件:

c1|c2|c3|c4|c5
c6|c7|c8|c9|c10
c11|c12|c13|c14|c15

我想对其进行格式化,以便每个记录的第一个字段是c11的宽度-第一个字段中最长的单元格:

c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

我了解我可以指定:

awk -F"|" '{printf "%-3s%s%s%s%s\n", $1, $2, $3, $4, $5}' file > newfile

假设我知道我希望第一列的宽度是多少,但是我不知道文件中有多少个字段。基本上我想做这样的事情:

... '{printf "%-3s|", $1}'

...,然后以其原始格式打印其余字段。


另一种方法来解决它:sed 's/|/'' '' '' |/;s/\(...\) */\1/'(可以添加额外的报价插入这3个空格作为SE意见挤连续的空格为一个)
斯特凡Chazelas

Answers:


14

您只能用于sprintf重新格式化$1

例如

$ awk 'BEGIN{OFS=FS="|"} {$1 = sprintf("%-3s",$1)} 1' file
c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

简而言之,您也可以在sprintf中使用动态格式设置:例如awk -vf1=3 'BEGIN{OFS=FS="|"}{$1=sprintf("%-*s",f1,$1)}1' test.txt
A.Danischewski

@ A.Danischewski-好吧,党 我从事大约17年的广泛awk编程工作,之前从未见过。想一想所有的麻烦就可以救我。
保罗·辛克莱

6

要找出第一个字段的最大/最长长度,然后根据该长度重新格式化字段中的值,您将必须对文件进行两次单独的遍历。

awk 'BEGIN     { OFS = FS = "|" }
     FNR == NR { if (m < (n=length($1))) m = n; next }
               { $1 = sprintf("%-*s", m, $1); print }' file file

(请注意,在命令行上两次指定了输入文件)

对于您提供的数据,这将产生

c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

第一步通过该FNR == NR块进行处理,该块仅跟踪迄今为止看到的最长字段(m包含看到的最大长度),然后跳至下一行。

第二遍由最后一个块处理,后者使用来重新格式化第一个字段sprintf()。格式字符串%-*s表示“左对齐的字符串,其宽度由保存实际字符串的参数之前的整数参数给定”。

显然,可以通过将标量m转换为包含每个列的最大宽度的数组来扩展为处理所有列:

$ awk 'BEGIN     { OFS = FS = "|" }
       FNR == NR { for (i=1; i<=NF; ++i) if (m[i] < (n=length($i))) m[i] = n; next }
                 { for (i=1; i<=NF; ++i) $i = sprintf("%-*s", m[i], $i); print }' file file
c1 |c2 |c3 |c4 |c5
c6 |c7 |c8 |c9 |c10
c11|c12|c13|c14|c15

1

钢铁司机建议的是聪明的方法。不必要的复杂方法是​​遍历每个字段:

$ awk -F'|' '{printf "%-3s|",$1; for(i=2;i<NF;i++){printf "%s|",$i} printf "%s\n", $i}' file
c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

但是公正sprintf $1并且完成它。


1
您已经倒退了一点,小而简洁的陈述通常比较复杂。在字段上进行迭代比较容易。
A.Danischewski,

1

在Awk中,您可以使用“ *”来生成动态printf格式字符串。

如果您已经知道长度,则可以使用-v传递第一列的字段长度。

awk -vcol1=3 'BEGIN{FS="|"}{for(i=1;i<=NF;i++){if(i==1)printf "%*-s%s",col1,$i,FS;else if(i!=NF)printf "%s%s",$i,FS;else printf "%s\n",$i;};}' test.txt

注意:如果您不知道第一列的长度是多少,可以将值存储在数组中,然后查找最大列长度,然后将其全部打印在END块中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.