awk去重awk奇数行

awk去重awk奇数行

# awk去掉重复行
root@bwhhkle:~# cat xx 
1xm
1xm
2
3ytd
3ytd
4
root@bwhhkle:~# awk '! a[$0]++' xx
1xm
2
3ytd
4
为什么能去掉重复的行?
首先"++"运算符优先级高于"!"取反;a[$0]因为未定义默认为空或空串,++数学运算会让其(a[$0])值变为0
又因为"++"先取值后运算,所以此时a[$0]++值为0,0为假,而"!"取反后变为真(awk里数字0,"",null三种假)
所以会执行默认的输出行。
接下来循环读取第二行时,a[$0]已经定义了(因为第一行和第二行一样,第一行是a[1xm],第二行也是是a[1xm]),所以此时a[$0]表示a[1xm];那么a[1xm]由于上一次的++运算,现在值已经变为了1,然后"!"取反后为假,那么就不执行默认的打印,即实现了去掉重复行(因为"! a[$0]++"第一次出现时为真,后面a[$0]重复出现时必然都为假awk的一个特性 awk 会根据语境来给未定义的变量赋初始值 
awk 'BEGIN{print a "" 1}'
1
 awk 'BEGIN{print a + 1}'
1

对于未定义的变量,如果要进行字符串操作,会被赋成空字符串 ""
  如果要进行数学运算,会被赋成数字 0
  现在我们看看上面的代码 ! a[$0] ++ 等价于 if(! a[$0] ++) print $0
  对于首次出现的记录,a[$0]的值是未定义的,由于后面的 ++ 是数学计算,所以a[$0]会被赋值成数字0
  也是由于 ++ 操作符,会先取值,再计算,所以对于第一行记录实际上是if(! 0) print $0
  ! 是取反,0 是假,! 0 就是真,那么就会执行后面的 print $0
  对于后面出现的重复记录,a[$0] 经过 ++ 的计算已经变为 1、2、3 ...
  而 ! 1  ! 2  ! 3 ... 都为假,不会打印

# 范例awk打印奇数行
root@bwhhkle:~# cat lines.bak 
1
2
3
4
5
6
7
8
root@bwhhkle:~# awk 'a=!a' lines.bak 
1
3
5
7