awk常用语法
awk命令用于对文件中匹配样式的记录进行输出,统计和其他处理操作。与sed命令相比,awk在对行的各个域进行处理时更有优势。
awk命令语法:
awk pattern { ACTION }
在awk读取文件的过程中中,变量$0保存整行的内容,变量$1保存第1个域的内容,$2保存第二个域的内容,…。
变量NF保存行包含的域的数量,因此变量$NF保存最后一个域的内容,$NF-1保存倒数第二个域的内容,…。
变量NR保存行的序号。
1.打印域
1)更换顺序打印域2,域1和域3。
awk '/^[^#]/{print $2, $1, $3}' /etc/fstab
/ /dev/mapper/rhel-root xfs
/boot UUID=722b5e8f-6da6-4eba-abfe-8c6e7fddd67b xfs
/u01 /dev/mapper/rhel-home xfs
swap /dev/mapper/rhel-swap swap
/dev/shm tmpfs tmpfs
2)打印每行含有的域数。
awk '/^[^#]/{print "Record:", NR, "has", NF, "fields."}' /etc/fstab
Record: 9 has 6 fields.
Record: 10 has 6 fields.
Record: 11 has 6 fields.
Record: 12 has 6 fields.
Record: 13 has 6 fields.
3)打印每个域的长度。
awk -F: '/oracle/{for(i=1;i<=NF;i++) print "Field",$i, "has", length($i), "letters."}' /etc/passwd
#将结果打印输出到文件/tmp/file.txt
awk -F: '{print "Field 1", "has", length($1), "letters." > "/tmp/file.txt"}' /etc/passwd
2.匹配样式后打印域
1)匹配swap行后再打印相关域。
awk '/swap/{print $2, $1, $3}' /etc/fstab
swap /dev/mapper/rhel-swap swap
2)匹配定义的CASE号规则后打印行。
echo "1-2345598" | awk '/^[0-9]+$/ || /^[0-9]-[0-9]+$/ {print}'
3)匹配|(或)定义的条件后打印行。
netstat -an |awk '/CLOSE_WAIT|ESTABLISHED|TIME_WAIT|LISTEN/ {print $0}'
4)匹配和打印两个日期之间的日志。
awk '/Sep 22/{a=1}a{b=b?b"\n"$0:$0;if(b~/Sep 23/){print b;b=""}}' messages-20210926
#使用'"和"'将变量包含在//符号里从而引用变量
date1='Sep 22'
date2='Sep 23'
awk ''"/$date1/"'{a=1}a{b=b?b"\n"$0:$0;if(b~'"/$date2/"'){print b;b=""}}' messages-20210926
或者直接在变量前后加上’“和"'引用变量。
awk '/'"$date1"'/{a=1}a{b=b?b"\n"$0:$0;if(b~/'"$date2"'/){print b;b=""}}' messages-20210926
sed命令也有类似的功能。
sed -n '/'"$date1"'/{p;:1;n;:2;/'"$date2"'/{p;b1};N;b2}' messages-20210926
3.BEGIN和END语句
在BEGIN语句中,可以存放在读取和处理文件前要执行的操作,一般用于打印报告的标题和更改内在变量的值。
在END语句中,用以存放文件的所有记录在被读取和处理后的操作,一般用于打印总结性的描述或数值总和。
awk 'BEGIN {print "Begin..."} ;/#[H-L]o/ {print $0}; /#P[e-o]/ {print $0} ;END{ print "The End"}' /etc/ssh/sshd_config
Begin...
#Port 22
#HostKey /etc/ssh/ssh_host_dsa_key
#LogLevel INFO
#LoginGraceTime 2m
#HostbasedAuthentication no
#PermitEmptyPasswords no
#PermitTTY yes
#PermitUserEnvironment no
#PidFile /var/run/sshd.pid
#PermitTunnel no
The End
4.分隔符
1)输入分隔符
变量FS保存域的输入分隔符,默认是空格或Tab。在awk命令中使用-F参数或者在BEGIN语句中定义FS变量可以更改域的输入分隔符值。
如果域分隔符同时有几种类型,使用双引号“”和中括号[]将各种分隔符放入其中(“[ :]”),或者使用双引号“”和或者符号|把各种分隔符包含在内(" |:")。
#获取系统用户的最大USER ID
awk -F: '{print $3}' /etc/passwd |sort -n |tail -1
多种输入分隔符示例:
cat file2
root /:root:/bin/sh
grid /u01/app:oinstall:/bin/bash
oracle /u01/app/oracle:dba:/bin/ksh
awk -F"[ :]" '{print $1, $3}' file2
root root
grid oinstall
oracle dba
awk 'BEGIN{FS=" |:"};{print $1, $3}' file2
root root
grid oinstall
oracle dba
awk 'BEGIN{FS="[ :]"};{print $1, $3}' file2
root root
grid oinstall
oracle dba
2)输出分隔符
变量OFS保存域的输出分隔符,默认是空格。
无输出分隔符示例:
awk 'BEGIN{FS="[ :]"};{print $1 $2 $3 $4}' file2
root/root/bin/sh
grid/u01/appoinstall/bin/bash
oracle/u01/app/oracledba/bin/ksh
默认以空格为输出分隔符示例:
awk 'BEGIN{FS="[ :]"};{print $1,$2,$3,$4}' file2
root / root /bin/sh
grid /u01/app oinstall /bin/bash
oracle /u01/app/oracle dba /bin/ksh
以Tab为输出分隔符示例:
awk 'BEGIN{FS="[ :]"};{print $1"\t"$2"\t"$3"\t"$4}' file2
root / root /bin/sh
grid /u01/app oinstall /bin/bash
oracle /u01/app/oracle dba /bin/ksh
awk 'BEGIN{FS="[ :]";OFS="\t"};{print $1,$2,$3,$4}' file2
root / root /bin/sh
grid /u01/app oinstall /bin/bash
oracle /u01/app/oracle dba /bin/ksh
5.变量NR
变量NR计算从文件中读入的行数,每读一行变量NR的值就更新一次。
读取文件完成后显示文件包含的行数:
grep -E -v "^#|^[ ]*$" /etc/fstab |awk '{print $2, $1} END {print "The number of lines of fstab is " NR}'
/ /dev/mapper/rhel-root
/boot UUID=722b5e8f-6da6-4eba-abfe-8c6e7fddd67b
/u01 /dev/mapper/rhel-home
swap /dev/mapper/rhel-swap
/dev/shm tmpfs
The number of lines of fstab is 5
输出第8行后的行的各个域:
awk 'NR>8 {print $2, $1, $3}' /etc/fstab
/ /dev/mapper/rhel-root xfs
/boot UUID=722b5e8f-6da6-4eba-abfe-8c6e7fddd67b xfs
/u01 /dev/mapper/rhel-home xfs
swap /dev/mapper/rhel-swap swap
/dev/shm tmpfs tmpfs
统计第8行以后每行包含的域数:
awk 'NR>8 {print NF}' /etc/fstab
6
6
6
6
6.使用外部变量和定义内部变量
如第2节所示,使用单引号加双引号‘“$var”’(使用双引号加单引号在某些Linux系统中可以某些Linux版本不可以,因此不建议使用)可以在awk命令中引用shell或脚本中定义的外部变量。
引用外部变量var示例:
var="priv1"
awk '/'"$var"'/{print $3}' /etc/hosts
rac1-priv1
rac2-priv1
定义内部变量counter示例:
awk '/^[^#]/{counter=counter+1;print} END {print "The number of lines of fstab is " counter "."}' /etc/fstab
/dev/mapper/rhel-root / xfs defaults 0 0
UUID=722b5e8f-6da6-4eba-abfe-8c6e7fddd67b /boot xfs defaults 0 0
/dev/mapper/rhel-home /u01 xfs defaults 0 0
/dev/mapper/rhel-swap swap swap defaults 0 0
tmpfs /dev/shm tmpfs defaults,size=21G 0 0
The number of lines of fstab is 5.
累计某列的值示例:
awk '{total=total+$2;print "Field 2 = " $2} END {print "Total=" total}' file3
Field 2 = 100000
Field 2 = 120000
Field 2 = 30000
Field 2 = 20000
Field 2 = 50000
Field 2 = 80000
Field 2 = 30000
Field 2 = 20000
Total=450000
统计符合某个分类的值:
awk 'BEGIN {Ncount=0;Scount=0}
BEGIN {printf "%s %10s %10s \n", "Record#", "Region", "Price"}
/north/ {printf "%6d %10s %10s \n",NR,$1,$2,Ncount=Ncount+1}
/south/ {printf "%6d %10s %10s \n",NR,$1,$2,Scount=Scount+1}
END {print "Total of North region is:", Ncount, "."}
END {print "Total of South region is:", Scount, "."}' file3
Record# Region Price
2 north 120000
3 northwest 30000
4 northeast 20000
6 south 80000
7 southeast 30000
8 southwest 20000
Total of North region is: 3 .
Total of South region is: 3 .
7.printf函数
printf以定义的格式输出字符和数字,语法如下:
printf(“字符串格式” [,数值])
字符串的格式包括%d(整数),%f(浮点数),%c(字符),%s(字符串)。
如果需要格式化字符串的宽度,则可以在以上格式中加上相应的数字,如%15s代表长度为15的字符串。
输出默认是右对齐,如果需要左对齐,则在%后加上-即可。
printf输出示例:
awk '/^[^#]/{printf("%-45s %-19s %-9s %-20s %-1d %1d \n", $1,$2,$3,$4,$5,$6)}' /etc/fstab
/dev/mapper/rhel-root / xfs defaults 0 0
UUID=722b5e8f-6da6-4eba-abfe-8c6e7fddd67b /boot xfs defaults 0 0
/dev/mapper/rhel-home /u01 xfs defaults 0 0
/dev/mapper/rhel-swap swap swap defaults 0 0
tmpfs /dev/shm tmpfs defaults,size=21G 0 0
8.awk if语句
在awk语句中,可以使用if来判断域是否满足定义的规则,并根据判断条件进行相应的操作。
在awk语句中if的使用格式如下:
if (判断条件) { 执行代码块1}
else { 执行代码块2 }
if (判断条件1) {
if (判断条件2) { 执行代码块1 }
else { 执行代码块2 }
}
1)比较数字
关系操作符 | 说明 |
---|---|
== | 等于 |
!= | 不等于 |
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
示例:
awk '{num= $2 / $3; if(num>5) print $1,num}' file3
east 10
north 13.3333
west 7.14286
south 10
2)比较字符串
关系操作符 | 说明 |
---|---|
== | 等于 |
!= | 不等于 |
~ | 包含正则表达式样式 |
!~ | 不包含正则表达式样式 |
示例:
awk '{if($1 ~ /north/) print $1, $3}' file3
north 9000
northwest 6000
northeast 5000
awk '{if($1 == "north") print $1, $3}' file3
north 9000
username="grid"
awk -F: '{if($4 ~/\<'"$username"'\>/) print $0}' /etc/group
dba:x:502:oracle,grid
asmadmin:x:504:grid
asmdba:x:506:grid,oracle
asmoper:x:507:grid
awk -F: '{if($4 ~/\<'"$username"'\>/) print $1}' /etc/group
dba
asmadmin
asmdba
asmoper
3)逻辑运算
逻辑运算符 | 说明 |
---|---|
&& | 逻辑与 |
|| | 逻辑或 |
! | 逻辑非 |
示例:
awk '{if($1 ~ /north/ && $3 > 5000) print $1, $3}' file3
north 9000
northwest 6000
4)数学运算
数学运算符 | 说明 |
---|---|
+ | 加 |
- | |
* | 乘 |
/ | 除 |
% | 求余 |
^ | 指数运算 |
++ | 变量加1 |
– | 变量减1 |
示例:
awk '/grid/{counter++;print} END {print "#The number of groups to which the user grid belongs is " counter "."}' /etc/group
dba:x:502:oracle,grid
asmadmin:x:504:grid
asmdba:x:506:grid,oracle
asmoper:x:507:grid
#The number of groups to which the user grid belongs is 4.
9.awk while语句
语法:
while (判断条件) 执行代码
while (判断条件) {
执行代码块
}
do {
执行代码块
} while (判断条件)
打印所有列示例:
awk '{i=1}; {while (i <= NF) {print $i; i++}}' file4
sdb
sdc
sde
sdf
sdg
sdi
10.awk for语句
语法:
for (初始条件语句; 判断条件; 每步条件变化语句)
{执行代码块}
for (数组的索引)
{执行代码块}
打印所有列示例:
awk '{for(i=1;i<=NF;i++)print $i}' file4
sdb
sdc
sde
sdf
sdg
sdi
以倒序打印文件的所有行:
cat file3
east 100000 10000
north 120000 9000
northwest 30000 6000
northeast 20000 5000
west 50000 7000
south 80000 8000
southeast 30000 6000
southwest 20000 4000
awk '{line[NR]=$0}; END{for(c=NR;c>0;c--)print line[c]}' file3
southwest 20000 4000
southeast 30000 6000
south 80000 8000
west 50000 7000
northeast 20000 5000
northwest 30000 6000
north 120000 9000
east 100000 10000
11.数组
在awk语句中,数组不需要定义就可以直接使用,而且数组的索引不需要是数字,任意与要存储的值相关的字符串都可以用来作为数组的索引(index)。
数组存储的值还可以使用以下方法来引用:
for (数组的索引)
{执行代码块}
统计某列中各个值的数量:
# cat file3
east 100000 10000
north 120000 9000
northwest 30000 6000
northeast 20000 5000
west 50000 7000
south 80000 8000
southeast 30000 6000
southwest 20000 4000
center 25000 5000
awk '{a[$3]++} END{for(i in a)print i,a[i]}' file3
10000 1
7000 1
8000 1
4000 1
9000 1
5000 2
6000 2
进程资源使用多少排序:
ps -eo 'user s pri pid ppid pcpu pmem vsz rss stime time nlwp psr args'|awk 'NR==1{print} NR!=1{r[++n]=$0} END{for(i in r)print r[i]|"sort -rn -k6 -k7"} '
USER S PRI PID PPID %CPU %MEM VSZ RSS STIME TIME NLWP PSR COMMAND
root S 19 2271 1 0.2 1.1 4700804 290364 Oct19 00:07:52 38 1 /u01/app/19.0.0/grid/jdk/jre/bin/java -server -Xms128m -Xmx256m -Djava.awt.headless=true -Ddi
sable.checkForUpdate=true -XX:ParallelGCThreads=5 oracle.rat.tfa.TFAMain /u01/app/19.0.0/grid/tfa/rac1/tfa_home
root S 19 1432 1 0.1 0.0 114156 2280 Oct19 00:03:58 1 2 /bin/sh /etc/init.d/init.ohasd run >/dev/null 2>&1 </dev/null
gdm S 19 2338 2211 0.0 0.5 3773248 141564 Oct19 00:00:43 33 2 /usr/bin/gnome-shell
rtkit S 18 985 1 0.0 0.0 196848 1732 Oct19 00:00:01 3 7 /usr/libexec/rtkit-daemon
rpc S 19 963 1 0.0 0.0 69220 1056 Oct19 00:00:00 1 2 /sbin/rpcbind -w
root S 90 376 2 0.0 0.0 0 0 Oct19 00:00:00 1 7 [irq/16-vmwgfx]
root S 39 931 2 0.0 0.0 0 0 Oct19 00:00:00 1 5 [xprtiod]
root S 39 930 2 0.0 0.0 0 0 Oct19 00:00:00 1 7 [rpciod]
root S 39 92 2 0.0 0.0 0 0 Oct19 00:00:00 1 5 [deferwq]
root S 39 905 2 0.0 0.0 0 0 Oct19 00:00:00 1 1 [xfs-eofblocks/d]
root S 39 904 2 0.0 0.0 0 0 Oct19 00:00:00 1 1 [xfs-log/dm-2]
12.awk内置函数
1)字符串函数
函数 | 说明 |
---|---|
gsub(r,s[,t]) | 使用字符串s替换字符串t中匹配正则表达式r的所有字符串。函数返回替换的次数。如果字符串t未提供,则缺省是$0。 |
sub(r,s[,t]) | 使用字符串s替换字符串t中匹配正则表达式r的第一个字符串。如果成功返回1,否则返回0。如果字符串t未提供,则缺省是$0。 |
index(str,substr) | 返回字符串substr在字符串str中第1次出现的位置,如果未找到则返回0 |
length(str) | 返回字符串的长度 |
match(s,r) | 在字符串s中匹配正则表达式r的字符串,返回正则表达式r在s中匹配开始的位置,如果未找到则返回0 |
split(string,array[,sep]) | 将字符串string分割成数组array,如果分隔符sep没有指定,则使用FS作为分隔符,返回数组的元素数量。 |
substr(string,m[,n]) | 返回字符串string在起始位置m和包含n个字符的子字符串。如果n没有提供,则返回从m开始直到字符串末尾的所有字符。 |
tolower(string) | 将所有大写字符串转换成小写字符串,返回新字符串。 |
toupperr(string) | 将所有小写字符串转换成大写字符串,返回新字符串。 |
取某列的子字符串再转换成大写:
cat file2
root /:root:/bin/sh
grid /u01/app:oinstall:/bin/bash
oracle /u01/app/oracle:dba:/bin/ksh
awk '{print toupper(substr($1,0,5))}' file3
EAST
NORTH
NORTH
NORTH
WEST
SOUTH
SOUTH
SOUTH
CENTE
替换某列的字符串:
awk -F "[ :]" '{sub("/bin/","",$4); print $4}' file2
sh
bash
ksh
取某列的子字符串再分割:
awk -F "[ :]" '{split(substr($4,match($4,"/bin/")),a,"/"); print a[3]}' file2
sh
bash
ksh
2)IO函数
函数 | 说明 |
---|---|
close(filename-expr) 或 close(command-expr) | 关闭文件或管道。 |
getline [var] [<file] 或 command | getline [var] | 从输入,文件或管道中读取下一行 |
next | 读取下一输入行,然后进入下一个循环执行样式和过程语句 |
delete array[element] | 删除数组array中的一个元素 |
print[args][destination] | 打印arg到目标输出。如果没有指定arg,默认是$0。如果destination没有指定,则输出到标准输出stdout。 |
printf(format [,expression(s)] [destination]) | 按照格式要求打印,详见上面的printf函数。 |
sprintf(format [,expression(s)] [destination]) | 返回格式化的字符串,不打印到输出。 |
system(command) | 执行系统命令,返回执行状态。 |
针对文件里的所有行调用系统命令:
awk -F: '{cmd="grep "$1" /etc/group";system(cmd)}' oracleuser|sort -u
asmadmin:x:504:grid
asmdba:x:506:grid,oracle
asmoper:x:507:grid
dba:x:502:oracle,grid
oracle:x:1000:
3)数学函数
函数 | 说明 |
---|---|
atan2(y,x) | 返回y/x的正切值 |
cos(x) | 返回x的余弦值 |
exp(arg) | 返回arg的自然指数e^arg |
int(arg) | 返回arg的整数值 |
log(arg) | 返回arg的自然对数lnarg |
rand() | 产生1个在0和1之间的随机数,函数返回相同的随机数,除非使用srand()函数指定了生成随机数种子 |
sin() | 返回x的正弦值 |
sqrt(arg) | 返回arg的平方根 |
srand(expr) | 指定生成随机数的种子,默认是以时间为种子 |
示例:
awk '{print atan2($2,$1)}' file5
1.10715