awk-命令讲解:
一、awk:
1.定义:
(1)在 Linux/UNIX 系统中,awk 是一个功能强大的编辑工具,逐行读取输入文本,默认以空格或tab键作为分隔符作为分隔。并按模式或者条件执行编辑命令。AMK信息的读入也是逐行指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理。
(2)可以在无交互的情况下实现相当复杂的文本操作,被广泛应用于 Shell脚本,完成各种自动化配置任务。
(3)总结:按命令找到指定行然后打印,awk默认操作是打印。
2.格式:
awk ‘(操作符) (怎么做)’ (处理对象)
3.工作过程:
(1)执行BEGIN{action;…}语句块中的语句。
(2)从文件或标准输入(stdin)中读取一行,然后执行{action;…}语句块,逐行扫描文件,从第一行到最后一行重复执行,直到文件全部读取完成。
(3)当读至输入流末尾时,执行END{action;…}语句块,BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。
(4)总结:先看BEGIN{action},这个模块读取操作,读文件的所有行,所有读取完毕后,一次执行。END{action}打印输出结果,对前面的结果作条件判断,还可用代码操作。
4.工作原理:
sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个“字段”然后再进行处理,且默认情况下字段的分隔符为空格或 tab 键。awk 执行结果可以通过 print 的功能将字段数据打印显示。
5.常用选项:
(1)常用:
选项 | 作用 |
---|---|
-F “分隔符” | 指明输入时用到的字段分隔符,默认是若干个连续的空白符 |
-v | 变量赋值 |
(2)常用符号:
选项 | 作用 |
---|---|
‘’ | ‘模式或条件{操作}’,{}外指定条件,{}内指定条件 |
, | 指定连续的行 |
|| | 指定不连续的行 |
&& | 表示且 |
(3)内置变量(不能用双引号,否则会被系统识别成字符串):
选项 | 作用 |
---|---|
$0 | 打印当前处理行的所有内容 |
$n | 对当前处理行的第n个字段(第n列) |
NR | 当前处理行的行号(序数) |
NF | 当前处理行的n个字段 |
FS | 列分隔符,指定每行文本的字段分隔符,输入内容的分隔符,默认为空格或制表位。与"-F"作用相同 用-F可以不加单引号 -F:,用FS必须用=“” |
OFS | 输出内容的列分隔符 |
RS | 行分隔符。awk从文件中读取资料时,将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录进行处理。预设值是"\n" |
Fillname | 被处理的文件名 |
(4)基本打印用法:
1.[root@test1 opt]# awk '0{print}' test.txt # 0和1放置{ }前,能够起到限制打印内容的作用(默认为"1"),如果为0,就不打印内容
[root@test1 opt]# awk '1{print}' test.txt
bk
pp
chanyeol
baekhyun
2. [root@test1 opt]# awk '{print $0}' test.txt #$0,代表整行内容;awk是逐行读取处理,配合$0,就是打印所有内容
$1只取第一列,可以对行切片,输出列
bk
pp
chanyeol
baekhyun
[root@test1 opt]# awk '{print NR}' test.txt #打印行号
1
2
3
4
[root@test1 opt]# awk '{print NR,$0}' test.txt #打印行号和内容
1 bk
2 pp
3 chanyeol
4 baekhyun
3. [root@test1 opt]# awk 'NR==3{print}' test.txt #指定打印第三行
chanyeol
[root@test1 opt]# awk 'NR==2,NR==4{print}' test.txt #指定打印2-4行
pp
chanyeol
baekhyun
[root@test1 opt]# awk 'NR==2;NR==4{print}' test.txt #指定打印第二行,第四行
pp
baekhyun
[root@test1 opt]# awk '(NR>=2)&&(NR<=4){print}' test.txt #用正则表达式打印2-4行
pp
chanyeol
baekhyun
(2)奇偶行打印:
[root@test1 opt]# awk 'NR%2==0{print}' test.txt #偶数行打印
pp
baekhyun
[root@test1 opt]# awk 'NR%2==1{print}' test.txt #奇数行打印
bk
chanyeol
(3)运算:
[root@test1 ~]# awk 'BEGIN{print 100+200}'
300
[root@test1 ~]# awk 'BEGIN{print 10.2*5.5}'
56.1
[root@test1 ~]# awk 'BEGIN{print 10.2/5.5}'
1.85455
[root@test1 ~]# awk 'BEGIN{print 2^5}'
32
二、内置函数:
1.getline的工作过程:
(1)当getline左右无重定向符号(“<”,“>”)或者管道符号(“|”)时,awk首先读取的是第一行,而getline获取的是光标跳转至下一行的内容(也就是第二行)。
(2)当getline左右有管道符号或重定向符时,getline则作用定向输入文件,由于文件是刚打开,并没有被awk读入一行,而只是getline读入,所以getline返回的是文件的第一行,而不是跳转至一行输入。
2.打印:
(1)基本运用:
[root@test1 opt]# awk '{print $0;getline}' test.txt #打印奇数行
bk
chanyeol
[root@test1 opt]# awk '{getline;print $0}' test.txt #打印偶数行
pp
baekhyun
(2)总结:
- getline是awk的内置函数。
- 没有重定向,管道符,就打印奇偶行。
- 重定向从指定文件获取内容,管道符相当于赋值变量。
3.文件内容匹配过滤打印:
(1)基础打印:
1.[root@test1 opt]# awk '/^root/{print}' /etc/passwd #只匹配以root开头的行
root:x:0:0:root:/root:/bin/bash
2.[root@test1 opt]# awk '/root/{print}' /etc/passwd #只匹配包含root的行
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
3.[root@test1 opt]# awk '/bash$/{print}' /etc/passwd #只匹配以bash结尾的行
root:x:0:0:root:/root:/bin/bash
wang:x:1000:1000:wang:/home/wang:/bin/bash
billkin:x:1001:1001::/home/billkin:/bin/bash
pp:x:1002:1002::/home/pp:/bin/bash
chanyeol:x:1003:1003::/home/chanyeol:/bin/bash
baekhyun:x:1004:1004::/home/baekhyun:/bin/bash
chanbaek:x:1005:1005::/home/chanbaek:/bin/bash
suho:x:1006:1006::/home/suho:/bin/bash
4.BEGIN,END模式:
(1)BEGIN打印模式:
- 格式:awk ‘BEGIN{…};{…};END{…}’ 文件
- 处理过程:在awk处理指定的文本之前,需要先执行BEGIN{…}模式里的命令操作。中间的{…} 是真正用于处理文件的命令操作,在awk处理完文件后才会执行END{…}模式里的命令操作。END{ }语句块中,往往会放入打印结果等语句。
- 固定格式:awk ‘BEGIN{X=1}(初始条件);{x++}(命令操作);END{print x}(打印结果)’ 文件名
(2)运用:
1. [root@test1 opt]# awk 'BEGIN{x=1};{x++};END{print x}' test1.txt
5
2.[root@test1 opt]# head -n5 /etc/passwd |awk -F: '{print $1}' #以冒号为分割,打印第一列
root
root
bin
daemon
adm
lp
(3)-v 变量赋值:
1. [root@test1 opt]# fs=":";awk -v FS=$fs -v OFS="+" '{print $1,$3}' /etc/passwd
root+0 # fs的列分隔符是:,然后使用-v给FS赋值=:,输入的时候FS是:,-v给OFS赋值输出的时候变量为+,然后打印第一列和第三列
bin+1
daemon+2
adm+3
lp+4
sync+5
shutdown+6
2. [root@test1 opt]# echo $PATH | awk -v RS=':' '{print $1}' #换行输出
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin
5.条件判断打印:
(1)指定区间打印:
[root@test1 opt]# awk -F : '$3>500{print $0}' /etc/passwd #uid大于500的
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
libstoragemgmt:x:998:996:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
colord:x:997:995:User for colord:/var/lib/colord:/sbin/nologin
(2)取反打印:
[root@test1 opt]# awk -F : '!$3<=10{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
(3)用if做条件判断来打印:
[root@test1 opt]# awk -F : '{if($3>10){print $0}}' /etc/passwd
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin #使用了if语句,内部条件(),外部条件{},整个加{}作为一条语句执行,相当于嵌套语法
三、awk的三元表达式:
1.格式:
(1)awk ‘(条件表达式)?(A表达式或者值):(B表达式或者值)’
(2)运用:
[root@test1 opt]# awk -F: '{max=($3>=$4)?$3:$4;{print max,$0}}' /etc/passwd|sed -n '1,6p'
2.awk的精确筛选:
(1)常用选项:
选项 | 作用 |
---|---|
$n(> < ==) | 用于对比数值 |
$n~“字符串” | 代表第n个字段包含某个字符串 |
$n!~“字符串” | 代表第n个字段不包含某个字符串 |
$n==“字符串” | 代表第n个字段为某个字符串 |
$n!=“字符串” | 代表第n个字段不为某个字符串 |
$NF | 代表最后一个字段 |
(2)基础运用:
1. [root@test1 opt]# awk -F: '$7~"bash" {print $1,$NF}' /etc/passwd
root /bin/bash # 输出第七个字段包含“bash”所在行的第一个字段和最后一个字段
wang /bin/bash
billkin /bin/bash
pp /bin/bash
chanyeol /bin/bash
baekhyun /bin/bash
chanbaek /bin/bash
suho /bin/bash
2.[root@test1 opt]# awk -F: '$7!~"nologin" {print $1,$NF}' /etc/passwd
root /bin/bash # 输出第七个字段不包含“nologin”所在行的第一个字段和最后一个字段
sync /bin/sync
shutdown /sbin/shutdown
halt /sbin/halt
wang /bin/bash
billkin /bin/bash
pp /bin/bash
chanyeol /bin/bash
baekhyun /bin/bash
chanbaek /bin/bash
suho /bin/bash
3.[root@test1 opt]# awk -F: '($6=="/home/wang")&&($7=="/bin/bash"){print $1,$NF}' /etc/passwd
wang /bin/bash指定第六个字段为/home/wang,第七个字段为/bin/bash,输出满足这些条件所在行的第一个和最后一个字段
3.数组:
(1)基础运用:
1.[root@test1 opt]# awk 'BEGIN{a[0]=1;a[1]=2;a[2]=3;print a[1]}'
2
2.[root@test1 opt]# awk 'BEGIN{a[0]=10 ; a[1]=20 ; a[2]=30;for(i in a)print i,a[i]}' #数组遍历
0 10
1 20
2 30
(2)去重:
[root@test1 opt]# awk '{a[$1]++};END{for(i in a){print i,a[i]}}' test1.txt
baekhyun 1
chanyeol 1
pp 3
bk 3