awk命令

Posted 我一个月改一次名

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了awk命令相关的知识,希望对你有一定的参考价值。


前言

sed 常用于对整行读取后进行处理;

awk 不仅能逐行处理,也能通过分隔符 获取具体每一列的值;

一、awk 介绍

awk 工作原理:

  • 逐行读取文本,默认以 空格 或 tab键 为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。

  • sed 命令常用于一整行的处理,而 awk 是将一行根据分隔符分成多个 “字段” 后再进行处理。

  • awk 信息的读入也是逐行读取的,执行结果可以通过 print 的功能将字段数据打印显示。

在使用 awk 命令的过程中,可以使用逻辑操作符:

  • “&&” 表示 “与”
  • “lI” 表示"或"
  • “!” 表示 “非”

还可以进行简单的数学运算:

  • +
  • -
  • *
  • /
  • % 取余
  • ^ 乘方

命令格式:

awk 选项 '模式或条件 [操作]' 文件1 文件2 ...

awk -f 脚本文件 文件1 文件2 ...
#通过脚本文件多个命令,达到批量操作的目的

awk 常见的内建变量:

FS:列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与选项"-F"作用相同

NF:当前处理的行的字段个数。

NR:当前处理的行的行号(序数)。

$0:当前处理的行的整行内容。

$n:当前处理行的第n个字段(第n列)。

FILENAME:被处理的文件名。

RS:行分隔符。
awk 从文件上读取资料时,将根据RS的定义把资料切割成许多条记录;
而awk一次仅读入一条记录进行处理。默认值是'\\n'

 awk 是 linux 下的一个命令,他对其他命令的输出,对文件的处理都十分强大,其实他更像一门编程语言,他可以自定义变量,有条件语句,有循环,有数组,有正则,有函数等。

 他读取/输出文件的方式是一行一行的读,根据你给出的条件进行查找,并在找出来的行中进行操作,感觉他的设计思想,真的很简单,但是结合实际情况,具体操作起来就没有那么简单了。

 有三种形势,awk,gawk,nawk,平时所说的awk其实就是gawk。

二、awk 操作

  • print 一定要写在 {} 中 ,即 {print}
  • {print} 一般放在表达式的最后面
  • BEGIN 表示开始执行的语句
  • END 是当 BEGIN 的语句执行结束后才会执行后面的语句
  • ~ 表示包含的意思,如:$1~'abc",表示 第一列包含 字符串 abc

2.1 按行输出文本

#输出文件所有内容,默认输出所有列($0)
awk '{print}' awkfile.txt  
awk '{print $0}' awkfile.txt

#输出文件第2列($2)的内容
awk '{print $2}' awkfile.txt

#输出有7列的行
awk 'NF==7 {print}' /etc/passwd

#输出大于等于第一行,小于等于第三行的内容
awk '(NR>=1)&&(NR<=3) {print}' awkfile.txt

在这里插入图片描述
我将第一行one 改成了 one first

awk '(NR%2==0) {print}' awkfile.txt
awk '/\\/bin\\/bash$/ {print}' /etc/passwd

在这里插入图片描述

BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的动作;
awk 在处理指定的文本之后,才回去执行END模式中指定的动作;
END{}语句块中,往往会放入打印结果等语句

#统计以字符串 bash 结尾的行数
#有bash的行数 x就加1,直达读取完文件内容后,输出x的值
awk 'BEGIN {x=0};/bash$/ {x++}; END {print x}' /etc/passwd

在这里插入图片描述

2.2 按字段输出文本

#输出用冒号分隔后的 第三列 字段
awk -F: '{print $3}' /etc/passwd
也能写成
awk -F ":" '{print $3}' /etc/passwd

在这里插入图片描述

#输出分割后的每行的第一个、第三个字段
awk -F ":" '{print $1,$3}' /etc/passwd

#第三列小于5 的第一列和第三列
awk -F ':' '$3<5 {print $1,$3}' /etc/passwd

#第三列小于1000的行
awk -F ':' '!($3<1000) {print}' /etc/passwd

#第三列小大于等于1000的行
# FS=":" 等同于 -F ":" 
awk 'BEGIN {FS=":"}; {if($3>=1000){print}}' /etc/passwd

#print的值设置为变量进行赋值
#三元运算符
#如果分割后的每行 第三列比第四列的值大,则把第三列的值赋值给max,
#否则就把第四个字段的值赋给max,输出该列
awk -F: '{max=($3>=$4)?$3:$4; {print max}}' /etc/passwd

在这里插入图片描述

#输出所有行和行号,每处理完一条记录,NR的值加1
awk -F ":" '{print NR,$0}' awkfile.txt

#输出以冒号分隔  第七个字段中包含/bash的行的第一个字段
awk -F ":" '$7~"/bash" {print $1}' /etc/passwd

#输出第一行包含root  有七个字段的行的 第一个 第二个字段,行数,列数
awk -F ":" '($1~"root")$$(NF==7) {print $1,$2,NR,NF}' /etc/passwd

#输出 第七列不是 /bin/bash 也不是 /sbin/nologin 行的行号和内容
awk -F ":" '($NF!="/bin/bash")&&($NF!="/sbin/nologin") {print NR,$0}' /etc/passwd

在这里插入图片描述

2.3 通过管道、双引号调用 Shell 命令

echo $PATH | awk 'BEGIN{RS=":"}; END{print NR}'
echo $PATH | awk 'BEGIN{RS=":"};{print $0}; END{print NR}'

#输出以root开头的行数
awk -F ":" '/^root/{print | "wc -l"}' /etc/passwd
等同
awk -F ":" '/^root/{print}' /etc/passwd | wc -l

在这里插入图片描述
在这里插入图片描述

#查看当前内存使用百分比
free -m | awk '/Mem/ {print int($3/($3+$4)*100)"%"}'

在这里插入图片描述

date -d "$(awk -F "." '{print $1}' /proc/uptime) second ago" +"%F %H:%M:%S"

#显示上次系统重启时间,等同于 update;
second ago 为显示多少秒前的时间;
+"%F %H:%M:%S" 等同于 +"%Y-%m-%d %H:%M:%S" 的时间格式

在这里插入图片描述
能够查看平均负荷 的命令有三个 uptime w top , 范围不超过7-8
在这里插入图片描述
awk 的 getline

第一种情况:

  • 当getline左右无重定向符 “<” 或 “|” 时,awk首先读取到了第一行,就是1,然后getline,就得到了1下面的第二行,就是2,因为getline之后,awk会改变对应的 NF,NR,FNR 和 $0 等内部变量,所以此时的 $0 的值就不再是1,而是2了,然后将它打印出来。

第二种情况:

  • 当 getline 左右有重定向符 "<“ 或 “|” 时,getline则作用于定向输入文件,由于该文件是刚打开,并没有被 awk 读入一行,只是 getline 读入,那么getline 返回的是该文件的第一行,而不是隔行。
#调用w命令,用来统计在线用户数
awk 'BEGIN {n=0; while("w" | getline) n++; {print n-2}}'

此时getline是上面的【第二种情况】,getline 只用于一行一样读入
#w 有四行,有两行不是用户登录信息,所以总行数n-2 就是当前登录的用户数了

再如:awk 'BEGIN {"hostname" | getline; {print $0}}'
输出的就是主机名所在的当前行

在这里插入图片描述
getline 再如:

seq 8 | awk '{getline; print $0}'

此时符合【第一种情况】,getline 会直接读取到下一行

在这里插入图片描述

测试:计算当前CPU使用/空闲率

#查看当前CPU空闲率, -b -n1 表示只需要1次的输出结果
top -b -n1 | grep Cpu | awk -F "," '{print $4}' | awk '{print $1"%"}'

在这里插入图片描述
写一个脚本文件,同时计算用户的使用率,内核的使用率之和信息。

#!/bin/bash
#description: 计算当前CPU使用率
#author:duan
#date:2021-05-20

echo CPU使用率:`top -b -n1 | grep "Cpu" | awk -F "," '{print $4}' | awk '{print $1"%"}'`

#ur=`top -b -n1 | awk -F, '/%Cpu/ {print $1}' | awk -F: '{print $2}' | awk '{print $1}'`
ur=`top -b -n 1 | grep Cpu | awk '{print $2}'`

#sy=`top -b -n1 | awk -F, '/%Cpu/ {print $2}' | awk '{print $1}'`
sy=`top -b -n 1 | grep Cpu | awk -F, '{print $2}' | awk '{print $1}'`
echo 用户使用率:$ur
echo 内核使用率;$sy

total=`echo "$ur+$sy"|bc`
echo "总使用率为:"$total

在这里插入图片描述
重新指定 分隔符

$1=$1 是用来激活$0的重新赋值,
也就是说
字段$1...和字段数NF的改变会促使awk重新计算$0的值,通常是在改变OFS后面需要输出$O时这样做


#指定分隔符,将分隔符空替换成|
echo "A B C D" | awk '{OFS="|"; print $0; $1=$1; print $0}'
或
echo "A B C D" | awk '{OFS="|"; print $0; $1=$1; print $0}'

在这里插入图片描述
在这里插入图片描述

2.4 awk 中使用数组

awk 'BEGIN{a[0]=10;a[1]=20; print a[1]}' 
20
awk 'BEGIN{a[0]=10;a[abc]=30; print a[abc]}' 
30
awk 'BEGIN{a["abs"]="abcd";a[abc]=20; print a["abs"]}' 
abcd
awk 'BEGIN{a["abs"]="abcd";a[abc]=20; print a[abs]}'
20   #下标不同,输出有问题
awk 'BEGIN{a[1]=10;a[2]=20;a[3]=30; for(i in a){ print i,a[i]}}' 
1 10
2 20
3 30

在这里插入图片描述

三、 使用 awk 小实验

要求:使用 awk 统计 httpd 访问日志中每个客户端IP的出现次数

结果:

awk '{ip[$1]++}END{for(i in ip){print ip[i],i}' /var/log/httpd/access_log | sort -r

备注:定义数组,数组名称为ip,数字的下标为日志文件的第1列(也就是客户端的IР地址),++的目的在于对客户端进行统计计数,客户端IP出现一次计数器就加1。END中的指令在读取完文件后执行,通过循环将所有统计信息输出,for循环遍历的是数组名ip的下标。

过滤密码失败的命令

awk 'BEGIN {ip[$11]=0}; /Failed password/ {ip[$11]++};END {for(i in ip){print i,ip[i]}}' /var/log/secure

其他命令
在这里插入图片描述

以上是关于awk命令的主要内容,如果未能解决你的问题,请参考以下文章

awk命令提取某行的最后一个数值

VSCode自定义代码片段——git命令操作一个完整流程

VSCode自定义代码片段——cli的终端命令大全

最佳 awk 命令

VSCode自定义代码片段4——cli的终端命令大全

VSCode自定义代码片段15——git命令操作一个完整流程