目录
awk简介
在 Linux/UNIX 系统中,awk 是一个功能强大的编辑工具,逐行读取输入文本,
默认以空格或tab键作为分隔符作为分隔,并按模式或者条件执行编辑命令。
以空格做为分隔符,多个空格他会自动压缩成一个
AWK信息的读入也是逐行指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理.
1、按照命令找指定的行 2、找到的行 打印,操作 awk默认的操作就是打印
可以在无交互 的情况下实现相当复杂的文本操作,被广泛应用于 Shell 脚本,完成各种自动化配置任务。
基本格式
awk ' <pattern><action><input-file>'
操作符 怎么干 处理对象
awk的工作过程
-
第一步:执行BEGIN{action;… }语句块中的语句
- 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
- 第三步:当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,
比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
END语句块在awk从输入流中读取完所有的行之后即被执行,
比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
pattern语句块中的通用命令是最重要的部分,也是可选的。
如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块
工作原理
sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个“字段”然后再进行处理,
且默认情况下字段的分隔符为空格或 tab 键。
awk 执行结果可以通过 print 的功能将字段数据打印显示
awk的基本格式
awk 选项 '模式或条件 {操作}' 文件1 文件2...
-F : “分隔符” 指明输入时用到的字段分隔符,默认的分隔符是若干个连续空白符
-v : var=value 变量赋值
注意一定是单引号:'模式或条件 {操作}'
{ }外指定条件,{ }内指定操作。
用逗号指定连续的行,用 || 指定不连续的行。&&表示”且“。
awk {print $1,$2,$3}
内置变量,不能用双引号括起来,不然系统会把它当成字符串。
内置变量
符号 | 说明 |
$0 | 当前处理的行的整行内容 打印所有 |
$n | 当前处理行的第n个字段(第n列) |
NR | 当前处理的行的行号(序数) |
NF | 当前处理的行的字段个数。$NF代表最后一个字段 |
FS | 列分割符。指定每行文本的字段分隔符,输入内容的分隔符, 默认为空格或制表位。与"-F"作用相同 用-F可以不加单引号 -F:,用FS必须用="" |
OFS | 输出内容的列分隔符 |
FILENAME | 被处理的文件名 |
RS | 行分隔符。awk从文件中读取资料时, 将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录进行处理。预设值是"\n" |
基本打印法
[root@localhost ~]# awk ''
#什么都不写 空没有效果
[root@localhost kyio]# awk '{print}'
11
11
22
22
[root@localhost opt]# awk '0{print}' test1.txt
[root@localhost opt]# awk '1{print}' test1.txt
two one one
twotwo
three three
four
0和1放置{ }前,能够起到限制打印内容的作用(默认为"1"),如果为0,就不打印内容
[root@shell 99]# awk '{print $0}' 1.txt #$0,代表整行内容;awk是逐行读取处理,配合$0,就是打
印所有内容
1123 hell world
231
34
1111
$1只取第一列,可以对行切片,输出列
[root@shell 99]# awk '{print $1}' 1.txt
1123
231
34
1111
[root@shell 99]# awk '{print NR}' 1.txt #打印行号,告诉我们有几行;
1
2
3
4
[root@shell 99]# awk '{print NR,$0}' 1.txt #不仅打印行号,还把每行对应的内用一起展示,
比sed展示的内容更直观
1 1123 hell world
2 231
3 34
4 1111
[root@shell 99]# awk 'NR==3{print}' 1.txt #指定打印出第三行的内容
34
[root@shell 99]# awk 'NR==3,NR==4{print}' 1.txt #打印3-5行的内容
34
1111
[root@shell 99]# awk 'NR==1;NR==4{print}' 1.txt #打印第一行和第四行
1123 hell world
1111
[root@shell 99]# awk '(NR>=2)&&(NR<=4){print}' 1.txt #正则的表达方式,打印2-4行的内容
231
34
1111
奇偶行打印
[root@localhost opt]awk 'NR%2==0{print}' test1.txt #打印偶数行
[root@localhost opt]awk 'NR%2==1{print}' test1.txt #打印奇数行
awk运算
[root@localhost home]# awk 'BEGIN{print 100+200}'
300
[root@localhost home]# awk 'BEGIN{print 10.2+20.3}'
30.5
[root@localhost home]# awk 'BEGIN{print 10.2*20.3}'
207.06
[root@localhost home]# awk 'BEGIN{print 10.2/20.3}'
0.502463
[root@localhost home]# awk 'BEGIN{print 10.2-20.3}'
-10.1
[root@localhost ~]# awk 'BEGIN{print 32}' #^和都是幂运算
9
[root@localhost ~]# awk 'BEGIN{print 2^3}'
8
getline的工作过程
-
当getline左右无重定向符号(“")或者管道符号(“|”)时,awk首先读取的是第一行,而getline获取的是光标跳转至下一行的内容(也就是第二行)。
-
当getline左右有管道符号或重定向符时,getline则作用定向输入文件,由于文件是刚打开,并没有被awk读入一行,而只是getline读入,所以getline返回的是文件的第一行,而不是跳转至一行输入
原因:getline运行之后awk会改变NF,NR,$0,FNR等内部变量,所以此时读取$0的行号不再为1,而是2
awk '{getline;print $0}' test1.txt #相当于打印了偶数行
awk '{print $0;getline}' test1.txt #相当于打印了奇数行
[root@localhost opt]# awk '{getline < "test1.txt"; print $0 > "test2.txt";}' test1.txt
#使用重定向把test1输出给test2
[root@localhost opt]# ls | awk '{getline line; print $0, line;}'
test1.txt test2.txt
#把ls的输出传递给getline函数,
line是变量 把ls的内容输出给变量,然后打印出结果,如果无内容,不做任何操作
文本内容匹配过滤打印:
BEGIN打印模式:
格式:awk 'BEGIN{...};{...};END{...}' 文件
处理过程
-
在awk处理指定的文本之前,需要先执行BEGIN{...}模式里的命令操作
-
中间的{...} 是真正用于处理文件的命令操作
-
在awk处理完文件后才会执行END{...}模式里的命令操作。END{ }语句块中,往往会放入打印结果等语句。
[root@localhost opt]# awk 'BEGIN{x=1};{x++};END{print x}' test1.txt
10
对字段进行处理打印:
[root@localhost opt]# head -n5 /etc/passwd |awk -F: '{print $1}' #已冒号为分割,打印第一列
root
bin
daemon
adm
lp
[root@localhost opt]# head -n5 /etc/passwd |awk -F: '{print $2}' #已冒号为分割,打印第二列
x
x
x
x
x
-v的用法:变量赋值
[root@localhost home]# fs=":";awk -v FS=$fs -v OFS="+" '{print $1,$3}' /etc/passwd
#fs的是:然后使用-v给FS赋值=:,输入的时候FS是:,-v给OFS赋值输出的时候变量为+,然后打印第一列和第三列
root+0
bin+1
daemon+2
adm+3
lp+4
a=3
b=4
num=$(awk -v a="$a" -v b="$b" 'BEGIN{print a + b}')
把shell的变量传给awk.
[root@localhost ~]#awk -v FS=':' -v OFS='==' '{print $1,$3}' /etc/passwd
root==0
bin==1
daemon==2
adm==3
lp==4
sync==5
[root@localhost ~]#echo $PATH | awk -v RS=':' '{print $1}'
#默认就是换行输出,不需要改
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin
BEIGIN模式指定
[root@shell 99]# head -n5 /etc/passwd|awk 'BEGIN{FS=":"};{print $5}'
root
bin
daemon
adm
lp
###---BEGIN模式在awk执行前改变分隔符,执行过程中,以“:”分割,打印指定内容
条件判断打印:
awk -F: '$3>500{print $0}' /etc/passwd
#uid大于500的
awk -F: '!($3>10){print $0}' /etc/passwd
#取反,uid小于10的行,所有列
awk -F: '{if ($3>500){print $0}}' /etc/passwd
#使用了if语句,内部条件(),外部条件{},整个加{}作为一条语句执行,相当于嵌套语法
awk的三元表达式与精准筛选用法
awk的三元表达式继承了java的用法,格式与Java相似
格式:
awk '(条件表达式)?(A表达式或者值):(B表达式或者值)'
awk -F: '{max=($3>=$4)?$3:$4;{print max,$0}}' /etc/passwd|sed -n '1,6p'
比较passwd文件中以":"为分割的第三个和第四个字段的大小,
max=($3>=$4)?$3:$4:这将变量 max 设置为输入行字段 3 和 4 之间的最大值。
? : 运算符是 if-else 语句的简写,因此此行等效于 if ($3 >= $4) { max=$3 } else { max=$4 }
取比较结果的最大值,赋值给变量max,并且输出max行的所有内容,然后打印其中的1-6行;
awk的精准筛选
字符 | 说明 |
$n(> < ==) | 用于对比数值 |
$n~"字符串" | 代表第n个字段包含某个字符串 |
$n!~"字符串" | 代表第n个字段不包含某个字符串 |
$n=="字符串" | 代表第n个字段为某个字符串 |
$n!="字符串" | 代表第n个字段不为某个字符串 |
$NF | 代表最后一个7字段 |
实例
输出第七个字段包含“bash”所在行的第一个字段和最后一个字段
awk -F: '$7~"bash" {print $1,$NF}' /etc/passwd
输出第七个字段不包含“nologin”所在行的第一个字段和最后一个字段
awk -F: '$7!~"nologin" {print $1,$NF}' /etc/passwd
指定第六个字段为/home/dn,第七个字段为/bin/bash,输出满足这些条件所在行的第一个和最后一个字段
awk -F: '($6=="/home/dn")&&($7=="/bin/bash"){print $1,$NF}' /etc/passwd
[root@localhost ~]# awk -F: '$7!="/bin/bash" {print $0}' /etc/passwd #取反
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
awk的分隔符用法
RS 指定行分隔符
awk从文件中读取资料时,将根据RS的定义把资料切割成许多条记录,
而awk一次仅读入一条记录进行处理。内置变量RS的预设值是"\n" 也就是换行。
也可以使用BEGIN模式在操作前进行行分隔符的改变
echo $PATH | awk 'BEGIN{RS=":"};{print NR,$0}' ---以":"分割,分割后逐行打印内容和行号
指定输出的分隔符:
OFS:输出内容的列分隔符。($n=$n用于激活,否则不生效,n必须存在)
对于输出时改变分隔符,我们常用到tr,awk,它们都可以实现在输出内容改变原本的分隔符
tr改变分隔符输出
[root@shell 99]# echo a b c d|tr " " ":"
a:b:c:d
awk改变输出分隔符
[root@shell 99]# echo a b c d|awk '{OFS=":";$1=$1;print $0}'
a:b:c:d
[root@shell 99]# echo a b c d|awk 'BEGIN{OFS=":"};{$2=$2;print $0}'
a:b:c:d
awk中定义数组打印
[root@shell 99]# awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;print a[1]}'
20
#awk中的数组形成遍历
[root@shell 99]# 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
#在awk中打印变量不需要加$
cat test3.txt
aaa
aaa
bbb
ccc
aaa
bbb
aaa
awk '{a[$1]++};END{for(i in a){print i,a[i]}}' test3.txt #在awk中打印变量不需要加$
检测运行机制
原理:a[$1]初始为0,a[$1]++后即为1
而这里awk中的a[$1]++最终的值是由test2.txt文本内容有多少行决定的,awk本身就是编程语言,不要按照shell来
文本逐行读取完毕后再执行END中的命令
awk会按行读取文件test2.txt的内容,然后逐个单词存储到数组a中。
每个单词都作为数组a的索引,所以每个单词都对应一个值,初始值为0。
读取文件的第一行,单词为 aaa,此时a[aaa]为0,执行 a[$1]++ 后,a[aaa]变成1。
读取文件的第二行,单词为 aaa,此时a[aaa]为1,执行 a[$1]++ 后,a[aaa]变成2。
读取文件的第三行,单词为 bbb,此时a[bbb]为0,执行 a[$1]++ 后,a[bbb]变成1。
读取文件的第四行,单词为 ccc,此时a[ccc]为0,执行 a[$1]++ 后,a[ccc]变成1。
读取文件的第五行,单词为 aaa,此时a[aaa]为2,执行 a[$1]++ 后,a[aaa]变成3。
读取文件的第六行,单词为 bbb,此时a[bbb]为1,执行 a[$1]++ 后,a[bbb]变成2。
读取文件的第七行,单词为 aaa,此时a[aaa]为3,执行 a[$1]++ 后,a[aaa]变成4。
最终,数组a中的元素值变成:a[aaa]=4,a[bbb]=2,a[ccc]=1。
实例引用
简单的日志分割
awk '{print $1, $7, $9}' /var/log/messages
在这个命令中,我们使用单引号将awk命令的操作包含起来。
$1、$7和$9是awk的内置变量,分别表示每行日志文件中的第1、第7和第9个字段。
通过使用print命令,我们将这些字段分别打印出来,以空格分隔。
最后,我们指定日志文件的路径/var/log/messages,awk会自动对文件中的每行进行处理并输出结果。
只分割前两行内容的第一个和第四个字段
awk 'NR<={print $1,$4}' /var/log/messages
取小数点几位和取整数
result=$(awk 'BEGIN{printf "%.2f", 2.3312.542}') #取小数点2位result=$(awk 'BEGIN{printf "%.F", 2.3312.542}') # 不取小数点,只取整数
提取host.txt主机名后再放回host.txt文件
1 www.kgc.com
2 mail.kgc.com
3 ftp.kgc.com
4 linux.kgc.com
5 blog.kgc.com
cat file.txt | awk -F '[ .]+' '{print $2}' >> host.txt
统计磁盘总共使用容量
df | tail -n +2 | grep -v tmpfs | awk '{sum+=$4} END{print "磁盘可用容量:"sum/1024/1024"G"}'
统计/etc下文件总大小
ls -l /etc | awk '/^-/{sum+=$5} END{print "文件总大小:"sum/1024"M"}'
CPU使用率
top -b -n 1
-b 告诉 top 以批处理模式运行,没有交互界面,这意味着它将输出结果到控制台一次,然后退出。
-n 1 指定 top 在退出之前应运行的迭代次数。在这种情况下,它只运行一次。
us 表示用户空间占用 CPU 百分比,sy 表示内核空间占用 CPU 百分比
[root@localhost network-scripts]# sum=$(top -b -n 1 | grep -w st |awk '{print $2+$4}')
[root@localhost network-scripts]# echo $sum
3.1
统计内存
#使用量
memory_used=$(free -m | grep "Mem:" |awk '{print $3 }')
#总计
memory_total=$(free -m | grep "Mem:" |awk '{print $2 }')
#打印内容:
echo '当前内存的使用量'$memory_used
echo '当前内存的总量'$memory_total
#计算百分比
z=$(echo "scale=2;${memory_used}/${memory_total}*100"|bc)
echo $z
b=$(echo $z | awk -F '.' '{print $1}')
echo $b
echo "当前的使用占比:${b}%"
if [ $b -lt 90 ]
then
echo "内存的使用量正常:${b}%
else
echo "内存的使用量为:"$b"大于90%,请注意!"
fi
监控硬盘
[root@localhost home]# df -h | grep -w centos-root | awk '{print $5}' | tr -d "%"
16%
[root@localhost home]# a=$(df -h | grep -w centos-root | awk '{print $5}') | tr -d "%"
[root@localhost home]# echo $a
16%
[root@localhost home]# b=$(echo "$a" | sed 's/%//g')
[root@localhost home]# echo $b
16