linux中awk的使用

参考文献:https://www.cnblogs.com/jiqianqian/p/7944013.html

awk是一个强大的文本分析工具。相较于sed常常一整行处理,awk则倾向于将一行数据切片,分成数个“字段”处理;简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

语法:

awk '条件类型1{动作1} 条件类型2{动作2} ...' filename
awk [options] 'pattern{action}' file

 1.查看最近5条登录用户和ip地址

awk工作流程是这样的:读入有’\n’换行符分割的一条记录,然后将记录按指定的域分隔符划分域1表示登录用户,$3表示登录用户ip,以此类推。

$ last -n 2|awk '{print $1"\t"$3}'
lzyer    192.168.56.1
reboot    boot
$ last -n 2|awk '{print $1,$3}'
lzyer 192.168.56.1
reboot boot
只处理第一行的数据
$ last -n 2|awk 'NR==1{print $1,$3}' lzyer 192.168.56.1

2.print和printf

参考:https://www.cnblogs.com/soymilk2019/p/12165545.html

awk中同时提供了print和printf两种打印输出的函数。

其中print函数的参数可以是变量、数值或者字符串字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。

printf函数用来格式化字符串,输出复杂时,printf更加好用,代码更易懂。

1. 使用printf输出的文本不会换行,如果需要换行,可以在对应的“格式替换符”后加入“\n”进行转义

2. 使用printf输出时,“指定的格式”与“被格式化的文本”之间,要用“,”隔开

3. 使用printf输出时,“格式”中的“格式替换符”必须与“被格式化的文本”一一对应(个数要相同)

eg:

1.#awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd 
输出:filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash 2.awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
输出:filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash
 printf函数用来格式化特别的输出,printf函数返回一个带格式的字符串给标准输出,printf语句包括一个加引号的控制串,控制串中可能嵌有若干格式说明和修饰符。控制串后面跟一个逗号,之后是一列由逗号分隔的表达式。printf函数根据控制串中的说明编排这些表达式的格式。与print函数不同的是, printf不会在行尾自动换行。因此,如果要换行,就必须在控制串中提供转义字符\n。
每一个百分号和格式说明都必须有一个对应的变量。要打印百分号就必须在控制串中给出两个百分号。请参考print转义字符和printf修饰符。格式说明由百分号引出,另外还列出了printf所用的格式说明符。
printf使用的转义字符
转义字符
定义
修饰符
定义
c
字符
-
左对齐修饰符
s
字符串
#
显示8 进制整数时在前面加个0
显示16 进制整数时在前面加0x
d
十进制整数
+
显示使用d 、e 、f 和g 转换的整数时,加上正负号+或-
ld
十进制长整数
0
用0而不是空白符来填充所显示的值
u
十进制无符号整数
格式说明符
功能
lu
十进制无符号长整数
%c
打印单个ASCII 字符
printf("The character is %c\n",x) 输出: The character is A
x
十六进制整数
%d
打印一个十进制数
printf("The boy is %d years old\n",y) 输出:The boy is 15 years old
lx
十六进制长整数
%e
打印数字的e 记数法形式
printf("z is %e\n",z) 打印: z is 2.3e+0 1
o
八进制整数
%f
打印一个浮点数
printf("z is %f\n", 2.3 * 2) 输出: z is 4.600000
lo
八进制长整数
%o
打印数字的八进制
printf("y is %o\n",y) 输出:z is 17
e
用科学记数法(e 记数法)表示的浮点数
%s
打印一个字符串
print("The name of the culprit is %s\n",$1) 输出:The name of the culprit is Bob Smith
f
浮点数
%x
打印数字的十六进制值
printf("y is %x\n",y) 输出:x is f
g
选用e或f中较短的一种形式
   
 
打印变量时,输出所在的位置称为"域"(field),域的宽度(width)是指该域中所包含的字符个数。下面这些例子中, printf控制串里的管道符(竖杠)是文本的一部分, 用于指示格式的起始与结束。
 
范例 $ echo "Linux" | awk '{printf "|%-15s|\n",$1}'
|Linux          |
说明:对于echo命令的输出,Linux是经管道发给awk。printf函数包含一个控制串。百分号让printf做好准备,它要打印一个占15个格、向左对齐的字符串,这个字符串夹在两个竖杠之间,并且以换行符结尾。百分号后的短划线表示左对齐。控制串后面跟了一个逗号和$1。printf将根据控制串中的格式说明来格式化字符串Linux。
范例 $ echo "Linux" | awk '{printf "|%15s|\n",$1}'
|          Linux|
说明:字符串Linux被打印成一个占15 格、向右对齐的字符串,夹在两个竖杠之间,以换行符结尾。
范例 $ cat employees
Tom   Jones 4424 5/12/66 543354
Mary  Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
$ awk '{printf "The name is: %-15s ID is %8d\n",$1,$3}' employees
The name is Tom             ID is 4424
The name is Mary            ID is 5346
The name is Sally           ID is 1654
The name is Billy           ID is 1683
说明:要打印的字符串放置在两个双引号之间。第一个格式说明符是%-15s,它对应的参数是$1,紧挨着控制串的右半边引号后面的那个逗号。百分号引出格式说明:短划线表示左对齐,15s表示占15格的字符串。这条命令用来打印一个左对齐、占15格的字符串,后面跟着字符串的ID和一个整数。
格式:%8d表示在字符串的这个位置打印$2 的十进制(整数)值。这个整数占8格,向右对齐。您也可以选择将加引号的字符串和表达式放在圆括号里。

3.正则匹配

搜索/etc/passwd有root关键字的所有行

awk -F: '/root/' /etc/passwd
输出:root:x:0:0:root:/root:/bin/bash

这种是pattern的使用示例,匹配了pattern(这里是root)的行才会执行action(没有指定action,默认输出每行的内容)。

搜索/etc/passwd有root关键字的所有行,并显示对应的shell,这里指定了action{print $7}

awk -F: '/root/{print $7}' /etc/passwd
输出:/bin/bash
匹配第四个字段中是否包含字符串“Techology”,若包含,打印该行
awk '$4 ~/Technology/' employee.txt

 操作符〜是正则表达式比较。如果匹配的默认操作,即打印整行.

4.awk内置变量

awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。

ARGC 命令行参数个数 
ARGV 命令行参数排列 
ENVIRON 支持队列中系统环境变量的使用 
FILENAME awk浏览的文件名 
FNR 浏览文件的记录数 
FS 设置输入域分隔符,等价于命令行 -F选项 
NF 浏览记录的域的个数 
NR 已读的记录数 
OFS 输出域分隔符 
ORS 输出记录分隔符 
RS 控制记录分隔符

 5.常见用法

1. -F指定分隔符,默认为空格

awk -F: 'NR==1{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

2. -v 替换变量

var1=100
echo |awk -v var=$var1 '{print var}'
100

3.使用内置变量FS指定输入分隔符,需要注意的是,使用变量时,要使用-v选项来指定对应的变量

awk -v FS=":" 'NR==1{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

awk -v FS=":" -v OFS="#" 'NR==1{print $1,$2}' /etc/passwd
root#x

指定多个分隔符[]

1.指定多个分隔符
[root@cxm ~]# cat 123
1111111111*222222222222222|33333333333#4444444444444&5555555555555555
#根据上边的文件,我们可以以* |#& 为分隔符
[root@cxm ~]# awk -F '[*|#&]' '{print $3}' 123
33333333333
[root@cxm ~]# awk -F '[*|#&]' '{print $4}' 123
4444444444444

 2.连续的分隔符为一个分隔符

[root@cxm ~]# cat 222
111111*****2222222|||||||3333333########444444444&&&&&&&&&55555555
#在[]后边加个+(加号)
[root@cxm ~]# awk -F '[*|#&]+' '{print $3}' 222
3333333
#默认连续不同的分隔符也会成为一个分隔符
[root@cxm ~]# cat 333
111111*|2222222|||||||3333333########444444444&&&&&&&&&55555555
[root@cxm ~]# awk -F '[*|#&]+' '{print $3}' 333
3333333
#*和|变成了一个分隔符

 

BEGIN、END 的使用

语法:BEGIN { Actions}
{ACTION} # Action for everyline in a file
END { Actions } # is for comments in Awk
举例:
1.打印报告
$ awk 'BEGIN {print "Name\tDesignation\tDepartment\tSalary";}
> {print $2,"\t",$3,"\t",$4,"\t",$NF;}
> END{print "Report Generated\n--------------";}' employee.txt

 2.计算整个文档的第四个字段中包含Technology字符串的行数

awk 'BEGIN {count=0;} $4 ~ /Technology/ {count++;} END {print "the number =",count;}' test_awk.txt

 6. 关系运算符

关系运算符 含义 用法实例
< 小于 x<y
<= 小于等于 x<=y
> 大于 x>y
>= 大于等于 x>=y
== 等于 x==y
!= 不等于 x!=y
~ 匹配 x~/正则表达式/
!~ 不匹配 x!~/正则表达式/

 

7.其他栗子

1.awk 打印除某列之外的所有列
1)awk '{ $3=""; print $0 }'   a.txt 将某列置为空,然后打印所有列。
2)获取详细时间 stat  a.json|grep 'Modify'|awk '{print $2,$3}' #2018-11-09 08:46:43.314788880
3)获取第二字段之后的所有值 stat  a.json|grep 'Modify'|awk '{$1=$2=""}1' #08:46:43.314788880 +0000
4)获取最后一列的值 awk -F',' '{print $NF}'  a.txt ,最后一列的值用$NF表示,倒数第二列用$(NF-1)表示。
5) 获取最后一行 awk 'END {print}' a.txt
6)  获取文件中的某几行 cat 1.txt |awk '{if ($1=="关键字")print $0}'
 
2.获取指定行的数据
获取第二行的数据 ps -a|grep logwriter|awk 'NR==2'
获取第一列第二列的数据 ps -a|grep logwriter|awk '{print $1,$2}' 
获取第二行第二列的数据 ps -a|grep logwriter|awk -F ': ' 'NR==2{print $2}'
 
3.awk打印从某一列到最后一列的内容
awk '{for(i=2;i<=NF;i++) printf("%s ",$i);print ""}' test_awk.txt
其中,print是分行打印,NF是最后一个域的索引值
 
4. 求最后一列的和
-F',' 指定分隔符为逗号,$NF为最后一列
awk -F',' '{sum += $NF};END{print sum}'
 
5.使用awk sed取出最后两个字段之外的字段
源字符串aa='/data/1learn_linux/test1/test2/learn_sed.txt',现只想要获取/data/1learn_linux/test1这一部分
1.使用sed
bb=`echo $aa|awk -F'/' '{print $(NF-1)"/"$NF}'`
echo $aa|sed -n "s@$bb@@gp" 由于字符串中含有/所以地址界定符用了@而不是/
2.使用awk
echo $aa |awk -F'/' '{gsub($(NF-1)"/"$NF,"");print}'
gsub(regular expression, subsitution string, target string);简称 gsub(r,s,t)即将字符串t中的r全部替换称s,其中t为指定域,省略时就默认使用整个记录。
sub匹配第一次出现的符合模式的字符串,相当于 sed 's//' 。
gsub匹配所有的符合模式的字符串,相当于 sed 's//g' 。
例如:
awk '{sub(/Mac/,"Macintosh");print}' file 用Macintosh替换Mac
awk '{sub(/Mac/,"MacIntosh",$1); print}' file 第一个域内用
 
6.awk提取指定字符串
路径名为 /home/ lxy/ hhhhh-a.bbb.cc.d (格式类型固定)
其中 现在我只想要 a.bbb.cc 这一段。
其中 hhhhh- 格式固定 ,a.bbb.cc.d 这一段长度有浮动,但前面的 a. 和后面的 .d 是固定的
解决方法:
如果/home/ lxy/ hhhhh-a.bbb.cc.d是文件中的字符串(即echo '/home/ lxy/ hhhhh-a.bbb.cc.d'>test.txt ),可以通过sed -n 's/.*hhhhh-\(.*\)\.d/\1/p' test.txt
其他方法:1.以'-'为分隔符,用cut取第二个字段(只要路径中不包含'-'即可):echo "/home/lxy/hhhhh-a.bbb.cc.d" | cut -d'-' -f2  但该方法只能取出a.bbb.cc.d
2.为防止路径中有'-',可以先取出文件名,在使用cut:echo "/home/lxy/hhhhh-a.bbb.cc.d" | awk -F/ '{print $NF}'| cut -d'-' -f2 但该方法只能取出a.bbb.cc.d
3.echo "/home/lxy/hhhhh-a.bbb.cc.d" | awk -F'-' '{print $2}' | cut -f 1-3 -d'.'
 
 7.awk 输出单引号,双引号
输出双引号:
awk '{print "\""}'        #使用“”双引号把一个双引号括起来,然后用转义字符\对双引号进行转义,输出双引号。

输出单引号:
awk '{print "'\''"}'       # 使用一个双引号“”,然后在双引号里面加入两个单引号‘’,接着在两个单引号里面加入一个转义的单引号\',输出单引号。

 8.awk 同时处理两行

处理第一行的时候,NR=1,NR%2!=0,执行了后面的a=$1,a=1

处理第二行的时候,NR%2==0,执行print a","$1"d"打印出来a和本行$1,即1,3d。再处理就是个循环过程。

9.删除指定行

从</root>行删除到最后行  sed -i '/<\/root>/d' a.xml

从第一行删除到<root>行  sed -i '/<root>/d' a.xml



posted @ 2018-05-07 12:06  声声慢43  阅读(2354)  评论(0编辑  收藏  举报