awk shell

awk:
在 Linux/UNIX 系统中,awk 是一个功能强大的编辑工具,逐行读取输入文本,
默认以空格或tab键作为分隔符作为分隔,并按模式或者条件执行编辑命令。
AWK信息的读入也是逐行指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理,可以在无交互 
的情况下实现相当复杂的文本操作,被广泛应用于 Shell 脚本,完成各种自动化配置任务。

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(小v) var=value 变量赋值

注意一定是单引号:'模式或条件 {操作}'
{ }外指定条件,{ }内指定操作。
用逗号指定连续的行,用 || 指定不连续的行。&&表示”且“。
内建变量,不能用双引号括起来,不然系统会把它当成字符串。

内置变量
$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,就不打印内容

awk '{print $0}' test1.txt ----$0,代表整行内容;awk是逐行读取处理,配合$0,就是打印所有内容
$1只取第一列,可以对行切片,输出列

[root@localhost opt]#awk '{print NR}' test1.txt ----打印行号,告诉我们有几行;

[root@localhost opt]#awk '{print NR,$0}' test1.txt ----不仅打印行号,还把每行对应的内用一起展示,
比sed展示的内容更直观

[root@localhost opt]#awk 'NR==3{print}' test1.txt    ----指定打印出第三行的内容
[root@localhost opt]#awk 'NR==3,NR==5{print}' test1.txt  ----打印3-5行的内容
[root@localhost opt]#awk 'NR==3;NR==5{print}' test1.txt  ----打印第三行和第五行
[root@localhost opt]awk '(NR>=3)&&(NR<=5){print}' test1.txt -----正则的表达方式,打印3-5行的内容

奇偶行打印:
[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 3**2}'  #^和**都是幂运算
9
[root@localhost ~]# awk 'BEGIN{print 2^3}'   
8


getline
getline的工作过程:
1、当getline左右无重定向符号(“<”)或者管道符号(“|”)时,
awk首先读取的是第一行,而getline获取的是光标跳转至下一行的内容(也就是第二行)。

2、当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的内容输出给变量,然后打印出结果,如果无内容,不做任何操作


文本内容匹配过滤打印:
awk '/^root/{print}' /etc/passwd
awk '/bash$/{print}' /etc/passwd

BEGIN打印模式:
格式:awk 'BEGIN{...};{...};END{...}' 文件
处理过程:
1、在awk处理指定的文本之前,需要先执行BEGIN{...}模式里的命令操作
2、中间的{...} 是真正用于处理文件的命令操作
3、在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

[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 $0}'
#默认就是换行输出,不需要改
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin


BEIGIN模式指定:
head -n5 /etc/passwd|awk 'BEGIN{FS=":"};{print $5}'
---BEGIN模式在awk执行前改变分隔符,执行过程中,以“:”分割,打印指定内容
head -n5 /etc/passwd|awk 'BEGIN{FS=":"};{print $3}'

条件判断打印:
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: 代表最后一个字段

实例1:输出第七个字段包含“bash”所在行的第一个字段和最后一个字段
awk -F: '$7~"bash" {print $1,$NF}' /etc/passwd

实例2:输出第七个字段不包含“nologin”所在行的第一个字段和最后一个字段
awk -F: '$7!~"nologin" {print $1,$NF}' /etc/passwd

实例3:指定第六个字段为/home/dn,第七个字段为/bin/bash,输出满足这些条件所在行的第一个和最后一个字段
awk -F: '($6=="/home/dn")&&($7=="/bin/bash"){print $1,$NF}' /etc/passwd

awk的分隔符用法:
RS 指定行分隔符:
awk从文件中读取资料时,将根据RS的定义把资料切割成许多条记录,
而awk一次仅读入一条记录进行处理。内置变量RS的预设值是"\n" 也就是换行。
也可以使用BEGIN模式在操作前进行行分隔符的改变
echo $PATH
echo $PATH | awk 'BEGIN{RS=":"};{print NR,$0}' ---以":"分割,分割后逐行打印内容和行号

指定输出的分隔符:
OFS:输出内容的列分隔符。($n=$n用于激活,否则不生效,n必须存在)
对于输出时改变分隔符,我们常用到tr,awk,它们都可以实现在输出内容改变原本的分隔符
 
tr改变分隔符输出
echo a b c d
echo a b c d|tr " " ":"

awk改变输出分隔符
echo a b c d|awk '{OFS=":";$1=$1;print $0}'
echo a b c d|awk 'BEGIN{OFS=":"};{$2=$2;print $0}'
 

awk结合数组运用
awk中定义数组打印:
awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;print a[1]}' 

awk中的数组形成遍历
awk 'BEGIN{a[0]=10 ; a[1]=20 ; a[2]=30;for(i in a)print i,a[i]}' #在awk中打印变量不需要加$

处理文件去重统计:
cat test2.txt
aaa
aaa
bbb
ccc
aaa
bbb
aaa 
                          
awk '{a[$1]++};END{for(i in a){print i,a[i]}}' test3.txt  #在awk中打印变量不需要加$

awk -v debug=1 '{print "Processing line", NR, "with value", $1; a[$1]++};END{for(i in a){print "Result for value", i, "is", a[i]}}' test2.txt
检测运行机制

原理: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<=2{print $1, $4}' /var/log/messages

取小数点几位和取整数
result=$(awk 'BEGIN{printf "%.2f", 2.331*2.542}') #取小数点2位
result=$(awk 'BEGIN{printf "%.F", 2.331*2.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 www.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 百分比


统计内存:

 
监控硬盘:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值