学习怎样使用 awk 的
!visited[$0]++
在不从新排序或改变原排列顺序的前提下删掉重复的行。html
假设你有一个文本文件,你须要删掉全部重复的行。node
要保持原来的排列顺序删掉重复行,使用:linux
awk '!visited[$0]++' your_file > deduplicated_file
复制代码
这个脚本维护一个关联数组,索引(键)为文件中去重后的行,每一个索引对应的值为该行出现的次数。对于文件的每一行,若是这行(以前)出现的次数为 0,则值加 1,并打印这行,不然值加 1,不打印这行。git
我以前不熟悉 awk
,我想弄清楚这么短小的一个脚本是怎么实现的。我调研了下,下面是调研心得:github
!visited[$0]++
对输入文件的每一行都执行。visited[]
是一个关联数组(又名映射)类型的变量。awk
会在第一次执行时初始化它,所以咱们不须要初始化。$0
变量的值是当前正在被处理的行的内容。visited[$0]
经过与 $0
(正在被处理的行)相等的键来访问该映射中的值,即出现次数(咱们在下面设置的)。!
对表示出现次数的值取反:
awk
中,任意非零的数或任意非空的字符串的值是 true
。visited[$0]
的值是一个比 0 大的数,取反后被解析成 false
。visited[$0]
的值为等于 0 的数字或空字符串,取反后被解析成 true
。++
表示变量 visited[$0]
的值加 1。
awk
自动把它转换为 0
(数字) 后加 1。总的来讲,整个表达式的意思是:数组
true
:若是表示出现次数为 0 或空字符串false
:若是出现的次数大于 0awk
由 模式或表达式和一个与之关联的动做 组成:bash
<模式/表达式> { <动做> }
复制代码
若是匹配到了模式,就会执行后面的动做。若是省略动做,awk
默认会打印(print
)输入。学习
省略动做等价于
{print $0}
。spa
咱们的脚本由一个 awk
表达式语句组成,省略了动做。所以这样写:unix
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: opensource.com/article/19/…
做者:Lazarus Lazaridis 选题:lujun9972 译者:lxbwolf 校对:wxy