【问题标题】:Only output line if value in specific column is unique如果特定列中的值是唯一的,则仅输出行
【发布时间】:2016-03-19 10:14:06
【问题描述】:

输入:

line1 a gh
line2 a dd
line3 c dd
line4 a gg
line5 b ef

期望的输出:

line3 c dd
line5 b ef

也就是说,我想仅在第 2 列中没有其他行包含相同值的情况下输出行。我以为我可以结合排序(例如 sort -k2,2 输入)和 uniq 来做到这一点,但似乎使用 uniq 我只能从左侧跳过列(-f 避免比较前 N 个字段)。当然有一些直接的方法可以用 awk 或其他东西来做到这一点。

【问题讨论】:

  • 你试过什么?我们这里的大多数人都很乐意帮助你提高你的手艺,但作为短期无偿编程人员不太乐意。在MCVE 中向我们展示您迄今为止的工作、您期望的结果和您得到的结果,我们将帮助您解决问题。

标签: awk


【解决方案1】:

您可以通过两次 awk 脚本来执行此操作:

awk 'NR==FNR{a[$2]++;next} a[$2]<2' file file

这会在文件中运行一次,递增数组中的计数器,其键是每行的第二个字段,然后运行第二次,仅打印计数器小于 2 的行。

您需要多次读取文件,因为在第一次读取期间的任何时候,您都不可能知道该行的第二个字段稍后是否会在文件中出现另一个实例。

【讨论】:

    【解决方案2】:

    这是一个一次性的awk 解决方案:

    awk '{a1[$2]++;a2[$2]=$0} END{for (a in a1) if (a1[a]==1) print a2[a]}' file
    

    但是,文件的原始顺序将会丢失。

    【讨论】:

    • 不是完全一通,是吗?第一遍从磁盘读取文件,第二遍从内存中读取文件。
    • @Graham:与awk '{actions}' file file相反,这是另一种方式。
    【解决方案3】:

    您可以结合使用 awk、grep、sort 和 uniq 来实现快速单行:

    grep -v "^[^ ]* $(awk '{print $2}' input.txt | sort | uniq -d) " input.txt

    编辑,避免使用正则表达式,\+ 和 \backreferences:

    grep -v "^[^ ]* $(awk '{print $2}' input.txt | sort | uniq -d | sed 's/[^+0-9]/\\&amp;/g') " input.txt

    【讨论】:

    • 我以前从未见过这样使用 grep。 ^[^ ]* 部分有什么作用?
    • @5heikki 第一个 ^ 将正则表达式锚定到行的前面,第二个 ^ 匹配所有不是空格的内容。
    • 所以在这种情况下,这将等效于 grep -v "^[^ ]* $(echo a)" 输入,但是,即使第 4 列由什么都没有,但它仍然有效。我只是不明白为什么..
    • 如果/当您匹配的文本包含 RE 元字符时,您会发现@ghoti 的答案继续有效,而此答案失败。这对你的数据来说可能很好,idk,但一般来说,从给定的样本输入中产生你期望的输出的答案是确定解决方案的起点,而不是终点——你必须真正思考每个答案是什么实际在做。
    • 大声感谢 Ed,我实际上在去年对那篇文章发表了评论。
    【解决方案4】:

    替代awk 以证明它仍然可以使用 sort 和 uniq 完成(有选项 -u 用于此),但是设置正确的格式需要一些杂耍(装饰/做东西/不装饰模式)。

    $ paste file <(cut -d' ' -f2 file) | sort -k2 | uniq -uf3 | cut -f1
    
    line5 b ef
    line3 c dd
    

    作为副作用,您会丢失原始排序顺序,如果您添加行号也可以恢复...

    【讨论】:

      猜你喜欢
      • 2011-02-20
      • 2017-01-11
      • 1970-01-01
      • 2022-10-09
      • 1970-01-01
      • 2021-04-27
      • 1970-01-01
      • 2021-12-26
      • 2015-10-01
      相关资源
      最近更新 更多