linux awk命令例子教程解读

发布时间:2020-01-24编辑:脚本学堂
有关awk命令的例子,awk 小例子解读,通过实例学习linux awk命令的用法,awk命令用于格式化输出匹配指定条件的字符串,感兴趣的朋友参考下。

1、awk '/555555*/' test
打印所有包含模式/555555*/的行

2、awk '{print $1}' test
打印文件的第一个字段,字段从行的左端开始,以空白符分隔

3:awk '{print $1,$3}' test
打印文件的第一,第三个字段

4:awk '/555555/{print $1,$3}' test
打印包含模式/555555/的第一,第三个字段

5:

awk '/zhangfei/{print "ttwu hu shangjiang:" $1,$2 "!"}'
wu hu shangjiang:zhangfei xiuhua!
 

t:制表符,tab键

6.打印数字时,可能需要控制数字的格式。这可以通过printf函数来实现,但是,通过设置一个特殊的awk变量OFMT,使用print函数时也可以控制数字的打印格式。OFMT的默认值时“%.6gd",表示只打印小数部分的前六位。
 

awk 'BEGIN{OFMT="%.2f";print 1.23456789,12E-2}'
1.23 0.12

如果设置了变量OFMT,在打印浮点数时,就只打印小数部分的前两位。百分号表示接下来要定义格式。
BEGIN:必须大写

7:

root@localhost tmp]# awk '{max=($1>$2)?$1:$2;print max}' filename

如果记录的第一个字段的值大于第二个字段的值,则把问号后面那个表达式的值赋给max,否则就将冒号后面的那个表单时的赋给max。

8、

awk -F: 'NF != 7{printf("line %d,does not have 7 fields: %sn",NR,$0)} $1 !~/[A-Za-z0-9]/{printf("line %d,nonalphanunmeric user id: %sn",NR,$0)} $2=="*"{printf("line %d,no password:%sn",NR,$0)}' passwd

awk的字段分隔 符是冒号;如果字段数(NF)不等于7,则执行接下来的操作块;printf函数打印字符串“line<行号>,does not have 7 fields:”,后面跟上当前记录的记录号(NR)和记录本身($0);如果第一个字段($1)中不含任何字母和数字字符,printf函数就打印字符 串“nonalphanumberic user id:”,后面跟上当前记录的记录号和内容;如果第二个字段是一个星号,就打印字符串“no passwd:",后面跟上记录号和记录本身。

9、用awk命令处理文件"grade.txt":
 

M.Tansley     05/99     48311     Green     8     40     44
J.Lulu     06/99     48317     green     9     24     26
P.Bunny     02/99     48     Yellow     12     35     28
J.Troll     07/99     4842     Brown-3     12     26     26
L.Tansley     05/99     4712     Brown-2     12     30     28
 
#打印整个文件
zhuyupeng@zhuyupeng-PC ~
$ awk '{print $0}' grade.txt
M.Tansley       05/99   48311   Green   8       40      44
J.Lulu          06/99   48317   green   9       24      26
P.Bunny         02/99   48      Yellow  12      35      28
J.Troll         07/99   4842    Brown-3 12      26      26
L.Tansley       05/99   4712    Brown-2 12      30      28

#打印第一和第四个域
zhuyupeng@zhuyupeng-PC ~
$ awk '{print $1,$4}' grade.txt
M.Tansley Green
J.Lulu green
P.Bunny Yellow
J.Troll Brown-3
L.Tansley Brown-2

#打印表头
zhuyupeng@zhuyupeng-PC ~
$ awk 'BEGIN {print "Name            Beltn---------------------------"}
> {print $1"t"$4}' grade.txt
Name            Belt
---------------------------
M.Tansley       Green
J.Lulu  green
P.Bunny Yellow
J.Troll Brown-3
L.Tansley       Brown-2

附,awk例子解读

awk ' NR < 11 '  #不规范,不建议,浪费时间

awk读取前11行(不包括第11行)。如前所述,这里省略了动作打印输出print。匹配模式是变量NR需要小于11,NR即为当前的行号。这个写法很简单,但是有一个问题,在NR大于10的时候,awk其实还是对每行进行了判断,如果文件很大,比如说有上万行,浪费的时间是无法忽略的。

因此,更好的写法是:
awk '1; NR = 10 { exit }'   #我的理解是从第一行开始读数据,将第10行到数据读完后退出。
第一句对当前行进行输出。第二句判断是不是已经到了第10行,如果是则退出。

输出文件的第一行(模拟 head -n filename  将n用1替代 )
awk 'NR > 1 { exit }; 1'
这个例子与前一个很相似,中心思想就是第二行就退出。

输出文件的最后两行(模拟 tail -n filename其中n取值为2 )
awk '{ y=x "n" $0; x=$0}; END { print y }'   #效率太低不推荐
第一句总是把一个在当前行前面再加上变量x的内容赋值给y,然后用x记录当前行内容。这样的效果是y的内容始终是上一行 加上当前行的内容。在最后,输出y的内容。如果仔细看的话,不难发现这个写法是很不高效的,因为它不停的进行赋值和字符串连接,只为了找到最后一行!所 以,如果你想要输出文件的最后两行,tail -n 2是最好的选择。

输出文件的最后一行(模拟 tail -n filename 其中n取值为1 )
awk 'END { print }'
句法方面没什么好说的,print省略参数即是等价于print $0。但是这个语句可能不能被非GNU awk的某些awk版本正常执行,如果为了兼容,下面的写法是最安全的:
awk '{ rec = $0 }; END { print rec }'   #这个写法更具有兼容性

输出只匹配某些模式的行(模拟 grep )
awk '/regex/'

输出不匹配某些模式的行(模拟 grep -v )
awk '!/regex/'
匹配模式前加“!”就是否定判断结果。

输出匹配模式的行的上一行,而非当前行
awk '/regex/ { print x }; { x = $0 }'
变量x总是用来记录上一行的内容,如果模式匹配了当前行,则输出x的内容。


输出匹配模式的下一行
awk '/regex/ { getline; print }'
这里使用了getline函数取得下一行的内容并输出。getline的作用是将$0的内容置为下一行的内容,并同时更新NR,NF,FNR变量。如果匹配的是最后一行,getline会出错,$0不会被更新,最后一行会被打印。

输出匹配AA  或  BB  或  CC的行
awk '/AA|BB|CC/'
正则表达式

输出长过65个字符的行
awk 'length > 64'
length([str])返回字符串的长度,如果参数省略,即是以$0作为参数,括号也可以省略了。
输出短于65个字符的行
awk 'length < 65'
和上例基本一样。

输出从匹配行到最后一样的内容
awk '/regex/,0'
这里使用了“pattern1,pattern2”的形式来指定一个匹配的范围,其中pattern2这里为0,也就是false,所以一直会匹配到文件结束。

从第8行输出到第12行
awk 'NR==8,NR==12'
同上例,这也是个范围匹配。

输出第52行
awk 'NR==52'  #不建议因为到了第52行awk还会继续往下读取下列的行。
如果想要少执行些不必要的循环,就这样写:
awk 'NR==52 {print;exit}'    #建议用这个写法

输出两次正则表达式匹配之间的行
awk '/regex1/, /regex2/'

删除所有的空行
awk NF        #  NF为真即是非空行。
另外一种写法是用正则表达式:
awk '/./'
这个很类似grep .的思路,但是是不如awk NF好的,因为“.”也是可以匹配空格和TAB的。

打印出空行行号
awk '/^$/{print NR}' filename
同理:打印出含有字符good的行号
awk '/good/{print NR}' filename

打印报告头和结尾    #没有验证,我也没看懂
awk 'BEGIN {print "numAtnumBn------------"} {print $1"t"$2} END {print "ENDAt ENDBn-----------"}' test.txt

numA    numB
------------
1       2
3       4

ENDA     ENDB
-----------

=============================
<            小于
<=        小于等于
==        等于
!=      不等于
>            大于
>=        大于等于
~         匹配正则表达式
!~      不匹配正则表达式

b        退格键
f      走纸换页
n      新行
r      回车键
t      tab键            #特别注意这几个红色字体,常用到
ddd    八进制值
c        任意其他特殊字符

例子------------
源文件:
 

[root@BJIT tmp]# more test.txt
1       a
3       b
5       c
7       a
9       b
15      c

用if判断匹配
 

[root@BJIT tmp]#  awk '{if($1>5) print $1}' test.txt         #将第一列中数值大于5的数值输出
7
9
15
[root@BJIT tmp]#  awk '{if($2~/a/) print $1}' test.txt   #如果第二列和a匹配,则输出他们对应的第一列到数值
1
7

用==号匹配——==                        #一个=是赋值的含义,两个==才是相等表条件
 

[root@BJIT tmp]# awk '$1=="3" {print $0}' test.txt     #如果第一列等于3则输出其在$0当前所有行对应的全部
3       b

匹配正则
 

[root@BJIT tmp]# awk '$1 ~ ".5" {print $1}' test.txt      #不是很理解注意5前有个小数点
15
[root@BJIT tmp]# awk '{if($2~/c/)print $1}' test.txt       #如果第2列有匹配的c则输出其对应在第一列的数值
5
15

关系匹配:
 

[root@BJIT tmp]# awk '$1 ~ "5|7" {print $0}' test.txt   #第一列中只要有5或者7匹配则输出其对应的全部
5       c
7       a
15      c

AND匹配——&&:
 

[root@BJIT tmp]# awk '$1=="5" && $2=="c" {print $0}' test.txt      #如果第一列有5且其在第二列中对应c则输出
5       c

或匹配——||:两边任意为真                      # 或不是一条竖线也可以吗,疑问?
 

[root@BJIT tmp]# awk '$2=="a" || $1=="15" {print $0}' test.txt
1        a
7        a
15      c

判断不匹配——!            # 感叹号在正则表达式中表示的是非,即否定的含义。
 

[root@BJIT tmp]# awk '$1!="3" {print $0}' test.txt   
1       a
5       c
7       a
9       b
15      c
[root@BJIT tmp]# awk '{if($2!~/a/) print $0}' test.txt
3       b
5       c
9       b
15      c

NR  和  NF
NR:记录已读的记录数
NF:浏览记录的域个数
 

[root@BJIT tmp]# awk '{print NR"t"NF"t"$0}' test.txt       # 注意这里到转义字符t表示tab占位符。
1       2       1       a
2       2       3       b
3       2       5       c
4       2       7       a
5       2       9       b
6       2       15      c

[root@BJIT tmp]# awk '{if(NR>0 && $1>7) print $0}' test.txt
9       b
15      c

[root@BJIT tmp]# awk '{if ($1==15)print $NF}' test.txt    $NF打印最后域 
c                      #   $NF表示的是变量NF的域,即她所对应的$0中最后一个数值。

域值比较(两种方法)
 

[root@BJIT tmp]# awk '{if($1<$2)print $0}' test.txt1       # 没有看懂
1       a
3       b
5       c
7       a
9       b
15      c
[root@BJIT tmp]# awk 'BEGIN {num=15}{if($1==num)print $0}' test.txt
15      c        #从数字15开始,如果第一列中变量的取值有等于15的就全部输出

修改数值域取值:
 

[root@BJIT tmp]# awk '{$1=$1-2;print $1}' test.txt     # 将第一列减去2之后在赋值给原来的数值
-1
1
3
5
7
13

[root@BJIT tmp]# awk '{if($1>2)($1="test"); print $0}' test.txt 
#  全部输出且如果第一列中有数值大于2,则用test替代。
1    a
test b
test c
test a
test b
test c

[root@BJIT tmp]# awk '{if($1==5){$1="test";print $1}}' test.txt
test

数值相加:
 

[root@BJIT tmp]# awk '{tot+=$1}; {print $1,$2} END{print tot}' test.txt
#   +=是一个正则表达式,再次即tot等于$1列中所有数字之和,因为$1表示的是列,而awk在执行的时候是逐行扫描读取的。 最后END输出这个tot的最终数值。
1  a
3  b
5  c
7  a
9  b
15 c
40

[root@BJIT tmp]#  awk '{tot+=$1}; {print $1,$2} END{print tot/100}' test.txt   
#  将相加的结果除以100   
1 a
3 b
5 c
7 a
9 b
15 c
0.4

替换字符串:                    (试验中替换成字母不成功)
 

[root@BJIT tmp]# awk 'gsub(/3/,123) {print $0}' test.txt
123     b

按照起始位置及长度返回字符串
 

[root@BJIT tmp]# more test2.txt
12345678
1234567
123456
12345
[root@BJIT tmp]# awk '{print substr($1,1,3)}' test2.txt
123
123
123
123
[root@BJIT tmp]# awk '$1==12345678 {print substr($1,1,5)}' test2.txt
12345
[root@BJIT tmp]# awk '$1==12345678 {print substr($1,3,5)}' test2.txt
34567
[root@BJIT tmp]# echo 12345678 | awk '{print substr ($1,3,6)}'
345678

字符
 

[root@BJIT tmp]# awk 'BEGIN {print "AtBnCtD"}'
A       B
C       D
 

删掉每行的最后一个字符
 

awk -F'|' '{print $1"|"$2"|"$3"|"$4}' filename
sed 's/.$//g' filename

源文件:
 

cat filename
1  2     3        4
1  2     3        4
1  2     3        4
1  2     3        4
 

将其中的空格都以tab键替换
 

awk '{print $1"t"$2"t"$3"t"$4}' filename
awk 'BEGIN {OFS="t"}{print $1,$2,$3,$4}'  filename