【问题标题】:How to print a line with no field separator in awk?如何在awk中打​​印一个没有字段分隔符的行?
【发布时间】:2020-12-06 08:00:09
【问题描述】:

我有这样的数据(文件名为list-in.dat)

a ; b ; c ; i
d
e ; f ; a ; b
g ; h ; i

我想要一个这样的列表(输出文件list-out.dat),其中包含所有项目,按字母顺序(不区分大小写)并且每个唯一项目只有一次。

a
b
c
d
e
f
g
h
i

我的尝试是:

awk -F " ; " ' BEGIN { OFS="\n" ; } {for(i=0; i<=NF; i++) print $i} ' file-in.dat | uniq | sort -uf > file-out.dat

但我最终得到了所有的蚂蚁除了那些只有一个项的行:

a
b
c
e
f
g
h
i

无论一行中有多少项目/如果缺少字段分隔符,我如何获取所有(唯一、排序的)项目?

【问题讨论】:

  • 所以要按字母顺序输出所有字段?
  • 是的,所有唯一字段
  • wrt for(i=0; - 字段编号(以及数组索引和字符串字符位置)在 awk 中从 1 开始,而不是 0。您的循环将打印$0(整个输入行),然后每个字段$1 到$NF。 wrt uniq | sort -u - uniq 需要排序的输入,而 sort -u 做了 uniq 和排序一样的工作,所以 uniq | sort -u 没有意义。不过,更重要的是,您的脚本中没有任何内容可以从一行中删除一个字段,并且该脚本绝对不会产生您所说的输出。发布您遇到问题的真实脚本,以便我们为您提供帮助。

标签: regex list sorting awk


【解决方案1】:

使用gnu-awk:

awk -F '[[:blank:]]*;[[:blank:]]*' '{
   for (i=1; i<=NF; i++) uniq[$i]
}
END {
   PROCINFO["sorted_in"]="@ind_str_asc"
      for (i in uniq)
         print i
}' file
a
b
c
d
e
f
g
h
i

对于non-gnu awk 使用:

awk -F '[[:blank:]]*;[[:blank:]]*' '{for (i=1; i<=NF; i++) uniq[$i]} 
END{for (i in uniq) print i}' file | sort 

【讨论】:

  • 将(非 gnu)答案视为“正确”,因为它是最快的解决方案(至少在我的系统上)。
  • 看起来首先填充uniq[] 而不是只打印每个字段对于某些数据分布来说更快。我刚刚使用awk 'BEGIN{for (i=1; i&lt;=100000; i++) for (j=1; j&lt;=10; j++) printf "%s%s", i+j, (j&lt;10?OFS:ORS)}' &gt; file 创建了一个文件,然后运行time awk '{for (i=1; i&lt;=NF; i++) unq[$i]} END{for (i in unq) print i}' file | sort &gt; /dev/null 使用real 0m0.475s user 0m0.389s sys 0m0.091s,同时运行time awk '{for (i=1; i&lt;=NF; i++) print $i}' file | sort -u &gt; /dev/null 使用real 0m2.321s user 0m2.343s sys 0m0.030s。你生活和学习......
  • 非常感谢 Ed 的基准测试。我想这也是 OP 在上面 cmets 中所说的。
  • 上述文件有很多重复值。对于awk 'BEGIN{for (i=1; i&lt;=1000000; i+=10) for (j=1; j&lt;=10; j++) printf "%s%s", i+j, (j&lt;10?OFS:ORS)}' &gt; file 创建的没有重复值的文件,两种方法的时间在real 0m3.196s user 0m3.139s sys 0m0.170s 附近几乎相同。因此,首先填充uniq[] 并在其上循环似乎是提高执行速度的更好方法,因为它从未变慢,有时甚至快得多。完全不是我的预期!
  • @EdMorton,感谢 TON Ed 先生和 anubhava 先生进行了这次愉快的交谈,我也从这次谈话中学到了,谢谢你们,你们两个 GEM 都保持安全 :)
【解决方案2】:
awk -F' ; ' -v OFS='\n' '{$1=$1} 1' ip.txt | sort -fu
  • -F' ; ' 设置空格后跟 ; 后跟空格作为字段分隔符
  • -v OFS='\n' 将换行符设置为输出字段分隔符
  • {$1=$1} 根据新的 OFS 更改 $0
  • 1打印$0
  • sort -fu 按字母顺序唯一忽略大小写

【讨论】:

    【解决方案3】:

    您能否尝试以下awk + sort 解决方案,并使用所示示例进行编写和测试。如果您想使用忽略大小写,请在 awk 代码中添加 IGNORECASE=1。

    awk '
    BEGIN{
      FS=" ; "
    }
    {
      for(i=1;i<=NF;i++){
        if(!a[$i]++){  print $i  }
      }
    }
    '  Input_file | sort
    

    说明:为上述添加详细说明。

    awk '                            ##Starting awk program from here.
    BEGIN{                           ##Starting BEGIN section of this program from here.
      FS=" ; "                       ##Setting field separator as space semi-colon space here.
    }
    {
      for(i=1;i<=NF;i++){            ##Starting a for loop till NF here for each line.
        if(!a[$i]++){  print $i  }   ##Checking condition if current field is NOT present in array a then printing that field value here.
      }
    }
    '  Input_file | sort             ##Mentioning Input_file name here and passing it to sort as Input to sort the data.
    

    【讨论】:

      猜你喜欢
      • 2015-02-04
      • 2014-04-27
      • 2014-10-14
      • 1970-01-01
      • 2017-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      相关资源
      最近更新 更多