【问题标题】:How to print the data that have largest length using awk?如何使用 awk 打印长度最大的数据?
【发布时间】:2018-06-05 13:03:38
【问题描述】:

我有这个输入:

1 happy,t,c,d
2 t,c
3 e,fgh,k
4 yk,j,f
5 leti,j,f,g

我想打印最大项目的长度(用逗号作为分隔符),它应该产生:

 1 5,1,1,1
 2 1,1
 3 1,3,1
 4 2,1,1
 5 4,1,1,1

然后我想为最终创建的第二列选择最大值:

 1 5
 2 1
 3 3
 4 2
 5 4

如何在awk 中执行此操作?

1) 对于我尝试的第一个任务:

awk -v col=$2 -F',' '{OFS=","; for(i=1; i<=NF; i++) print length($i);}' test.data.txt

没有输出正确的数据:

7
1
1
1
3
1
3
3
1
4
1
1
6
1
1
1

唯一的问题是我无法正确使用-v 选项来仅读取该列。因此,我将所有数据放在一列中,并从 column1 和 column1 和 column2 之间添加(从长度)值。

2) 要选择最大值,我在做:

awk -F',' '{OFS="\t"; m=length($1); for(i=1; i<=NF; i++) if (length($i) > m) m=length($i); print m}' test.data.txt

这可以正常工作,但由于第一列的存在,值被添加到给我的最大值:

7
3
3
4
6

代替:

5
1
3
2
4

最后,我想一次性合并这两个过程。有什么改进建议吗?

【问题讨论】:

    标签: bash awk gawk


    【解决方案1】:
    awk -F'[, ]' -v OFS="," '{m=length($2);for (i=3;i<=NF;i++) if (length($i) > m) m=length($i)}{print $1,m}' file
    1,5
    2,1
    3,3
    4,2
    5,4
    

    对于第一种情况:

    awk -F'[, ]' -v OFS="," '{printf "%s",$1;for (i=2;i<=NF;i++) printf "%s%s",(i==2?" ":OFS),length($i)}{print ""}'
    1 5,1,1,1
    2 1,1
    3 1,3,1
    4 2,1,1
    5 4,1,1,1
    

    更短的选择:

    awk -F'[, ]' -v OFS="," '{printf "%s ",$1;for (i=2;i<=NF;i++) printf "%s%s",length($i),(i==NF?ORS:OFS)}'
    

    虽然 awk 中的 print 打印数据并通过在末尾打印新行来更改行,但 printf 不会自行更改行。

    PS:感谢 Ed Morton 的宝贵意见。

    【讨论】:

      【解决方案2】:

      我们从这个数据文件开始:

      $ cat data
      1 happy,t,c,d
      2 t,c
      3 e,fgh,k
      4 yk,j,f
      5 leti,j,f,g
      

      对于第一个任务:

      $ awk '{n=split($2,a,/,/); printf "%2s %s",$1,length(a[1]); for(i=2; i<=n; i++) printf ",%s",length(a[i]); print""}' data
       1 5,1,1,1
       2 1,1
       3 1,3,1
       4 2,1,1
       5 4,1,1,1
      

      第二个任务:

      $ awk '{n=split($2,a,/,/); max=length(a[1]); for(i=2; i<=n; i++) if (length(a[i])>max)max=length(a[i]); print $1,max}' data
      1 5
      2 1
      3 3
      4 2
      5 4
      

      工作原理

      第二个任务:

      • n=split($2,a,/,/)

        我们将字段2的内容拆分成数组a

      • max=length(a[1])

        我们将数组a的第一个元素的长度分配给awk变量max

      • for(i=2; i&lt;=n; i++) if (length(a[i])&gt;max)max=length(a[i])

        如果数组a 的任何后续元素大于max,我们更新`max。

      • print $1,max

        我们打印第一个字段和max的值。

      【讨论】:

      • max=length(a[i]) :)
      • @PesaThe 哎呀!谢谢你。 1 的答案更新为 i
      【解决方案3】:

      试着打高尔夫:

      gawk -F'[ ,]' '{m=0;for(i=2;i<=NF;i++){l=length($i);if(l>m)m=l}print$1,m}'
      
      perl -MList::Util=max -F'\s+|,' -lne'$,=" ";print shift(@F),max map{length}@F'
      perl -MList::Util=max -F'\s+|,' -lne'print"@{[shift(@F),max map{length}@F]}"'
      perl -MList::Util=max -F'\s+|,' -lpe'$_="@{[shift(@F),max map{length}@F]}"'    
      
      ruby -F'[ ,]' -lape'$_="#{$F[0]} #{$F[1..-1].map{|e|e.size}.max}"'
      

      【讨论】:

      • 关于那个 awk 答案没有什么 gawk 特定的,它可以在任何 awk 中工作,你不应该使用字母 l 作为变量名,因为它看起来太像数字 @ 987654324@ 等会混淆您的代码。
      • 嗯,它是高尔夫,所以混淆了领土。我原以为并非所有 awks 都支持 FS 中的正则表达式
      • 只有旧的、损坏的 awk(Solaris 上的 /bin/awk)不支持 FS 中的正则表达式,但它也不支持许多其他的东西,通常是损坏的,并且绝对不能这样使用不值得在每个脚本上说“......除了旧的,坏掉的 awk”,只是假设没有人使用它。有关它的一些问题,请参阅 awk.freeshell.org/oawk
      • 顺便说一句! awk -F'[ ,]' '{m=0;while(NF--&gt;2){l=length($NF);if(l&gt;m)m=l}print$1,m}' file。警告 - 这将适用于我所知道的任何 awk 但递减 NF 的效果在技术上是每个 POSIX 未定义的行为。当人们依靠 NF-- 删除记录的最后一个字段时,这会成为一个更大的问题,然后是 YMMV,具体取决于您使用的 awk,但这里不是这种情况。
      猜你喜欢
      • 2022-11-16
      • 2016-04-04
      • 2011-05-17
      • 2021-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-19
      • 1970-01-01
      相关资源
      最近更新 更多