学习怎样使用 awk 的 !visited++ 在不重新排序或改变原排列顺序的前提下删掉重复的行。-- Lazarus Lazaridis(作者)
假设你有一个文本文件,你需要删掉所有重复的行。
要保持原来的排列顺序删掉重复行,使用:
awk '!visited[$0]++' your_file > deduplicated_file
这个脚本维护一个关联数组,索引(键)为文件中去重后的行,每个索引对应的值为该行出现的次数。对于文件的每一行,如果这行(之前)出现的次数为 0,则值加 1,并打印这行,否则值加 1,不打印这行。
我之前不熟悉 awk,我想弄清楚这么短小的一个脚本是怎么实现的。我调研了下,下面是调研心得:
总的来说,整个表达式的意思是:
awk 由 模式或表达式和一个与之关联的动作 组成:
<模式/表达式> { <动作> }
如果匹配到了模式,就会执行后面的动作。如果省略动作,awk 默认会打印(print)输入。
省略动作等价于 {print $0}。
我们的脚本由一个 awk 表达式语句组成,省略了动作。因此这样写:
awk '!visited[$0]++' your_file > deduplicated_file
等于这样写:
awk '!visited[$0]++ { print $0 }' your_file > deduplicated_file
对于文件的每一行,如果表达式匹配到了,这行内容被打印到输出。否则,不执行动作,不打印任何东西。
uniq 命令仅能对相邻的行去重。这是一个示例:
$ cat test.txt A A A B B B A A C C C B B A $ uniq < test.txt A B A C B A
我们也可以用下面的 sort 命令来去除重复的行,但是原来的行顺序没有被保留。
sort -u your_file > sorted_deduplicated_file
上面的方法会产出一个去重的文件,各行是基于内容进行排序的。 通过管道连接命令 可以解决这个问题。
cat -n your_file | sort -uk2 | sort -nk1 | cut -f2-
工作原理
假设我们有下面一个文件:
abc ghi abc def xyz def ghi klm
cat -n test.txt 在每行前面显示序号:
1 abc 2 ghi 3 abc 4 def 5 xyz 6 def 7 ghi 8 klm
sort -uk2 基于第二列(k2 选项)进行排序,对于第二列相同的值只保留一次(u 选项):
1 abc 4 def 2 ghi 8 klm 5 xyz
sort -nk1 基于第一列排序(k1 选项),把列的值作为数字来处理(-n 选项):
1 abc 2 ghi 4 def 5 xyz 8 klm
最后,cut -f2- 从第二列开始打印每一行,直到最后的内容(-f2- 选项:留意 - 后缀,它表示这行后面的内容都包含在内)。
abc ghi def xyz klm
以上为全文。
via: https://opensource.com/article/19/10/remove-duplicate-lines-files-awk
作者: Lazarus Lazaridis 选题: lujun9972 译者: lxbwolf 校对: wxy
本文由 LCTT 原创编译, linux中国 荣誉推出