假设您有一个文本文件,并且需要删除其所有重复行。
TL; DR
要在保留文件中顺序的同时删除重复的行,请使用:
awk '!visited[$0]++' your_file > deduplicated_file
这个怎么运作
索引等于文件的唯一行, 值等于它们的出现次数。 对于文件的每一行,如果行出现次数为零,则将它们增加一并打印该行 ;否则,它只是增加出现次数而无需打印该行 。我对awk并不熟悉,所以我想了解如何通过这么短的脚本( awk病房)来实现。 我做了研究,这是怎么回事:
- 对输入文件的每一行执行awk“ script” !visited [$ 0] ++ 。
- visit []是类型为关联数组 (又称为Map )的变量。 我们不必初始化它,因为awk会在我们第一次访问它时进行它。
- $ 0变量保存当前正在处理的行的内容。
- Visited [$ 0]使用等于$ 0的键(正在处理的行)访问存储在地图中的值,也就是出现次数(我们在下面设置)。
- ! 否定事件的值:
- 在awk中, 任何非零数字值或任何非空字符串值均为true 。
- 默认情况下, 变量被初始化为空字符串 ,如果转换为数字则为零。
- 话虽如此:
- 如果visit [[0]]返回一个大于零的数字,则该否定解析为false 。
- 如果visit [[0]]返回一个等于零的数字或一个空字符串,则该否定解析为true 。
- ++操作将变量的值( Visited [$ 0] )增加一。
- 如果该值为空, awk会自动将其转换为0 (数字),然后将其增加。
- 注意:在访问变量的值之后,将执行该操作。
总结起来,整个表达式的计算结果为:
- 如果出现的是零/空字符串,则为true
- 如果出现的次数大于零,则返回false
awk语句由pattern-expression和关联的action组成 。
< pattern / expression > { < action > }
如果模式成功,那么将执行关联的操作。 如果我们不提供动作awk ,则默认情况下,将输入内容打印出来 。
省略的动作等效于{print $ 0} 。
我们的脚本由一个带有表达式的awk语句组成,省略了动作。 所以这:
awk '!visited[$0]++' your_file > deduplicated_file
等效于此:
awk '!visited[$0]++ { print $0 }' your_file > deduplicated_file
对于文件的每一行,如果表达式成功,则将该行打印到输出。 否则,将不执行该操作,并且不会打印任何内容。
为什么不使用uniq命令?
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命令删除重复的行,但不会保留行顺序 。
sort -u your_file > sorted_deduplicated_file
使用cat进行排序和剪切
先前的方法将生成一个去重复的文件,其行将基于内容进行排序。 用一堆命令可以克服此问题:
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
参考资料
就这样。 猫的照片。
本文最初是在CC BY-NC 4.0许可下由Lazarus Lazaridis出现在iridakos博客上的,并在获得作者许可的情况下重新发布。
翻译自: https://opensource.com/article/19/10/remove-duplicate-lines-files-awk