shell脚本四剑客之awk详解

Posted 互联网老辛

tags:

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

文章目录

awk的介绍

shell脚本中最难的不是shell的语法难,而是在shell编程这门语言中,又突然出来一门编程语言,这个编程语言叫: awk

awk以用来处理数据和生成报告(excel);
处理的数据可以是一个或多个文件;可以是直接来自标准输入,也可以通过管道获取标准输入;

awk可以在命令行上直接编辑命令进行操作,也可以编写成awk程序来进行更为复杂的运用。

awk能够干什么

学习具体使用前,先来看下 awk 能干些什么事情:

  1. 能够将给定的文本内容,按照我们期望的格式输出显示,打印成报表。
  2. 分析处理系统日志,快速地分析挖掘我们关心的数据,并生成统计信息;
  3. 方便地用来统计数据,比如网站的访问量,访问的 IP 量等;
  4. 通过各种工具的组合,快速地汇总分析系统的运行信息,让你对系统的运行了如指掌;
  5. 强大的脚本语言表达能力,支持循环、条件、数组等语法,助你分析更加复杂的数据;
    6
    awk 不是万能的,它比较擅长处理格式化的文本,比如 日志、csv 格式数据等;

awk的格式

简单结构:
awk [选项] ‘模式 动作’ 输入文件

awk [options] ‘patternattion’ file

  • 模式即pattern,可以类似理解成sed的模式匹配,可以由表达式组成,也可以是两个正斜杠之间的正则表达式。比如NR==1,这就是模式,可以把它理解为一个条件。

  • 动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。

详细结构

awk ‘BEGIN print “start” pattern commands END print “end” ’ filename

一个 awk 脚本通常由 BEGIN 语句 + 模式匹配 + END 语句三部分组成,这三部分都是可选项

工作原理:

简单版:
第一步执行 BEGIN 语句
第二步从文件或标准输入读取一行,然后再执行 pattern 语句,逐行扫描文件到文件全部被读取
第三步执行 END 语句

详细执行流程:

  • 首先执行关键字 BEGIN 标识的 中的命令;
  • 完成 BEGIN 大括号中命令的后,开始执行 body 命令;
  • 逐行读取数据,默认读到 \\n 分割的内容为一条 记录,其实就是行的概念;
  • 将记录按照指定的分隔符划分为 字段,其实就是列的概念;
  • 循环执行 body 块中的命令,每读取一行,执行一次 body,最终完成 body 执行;
  • 最后,执行 END 命令,通常会在 END 中输出最后的结果;

awk 是输入驱动的,有多少输入行,就会执行多少次 body 命令

我们在学习过程中,要时刻记着:

记录 (Record) 就是行
字段 (Field) 就是列
BEGIN 是预处理阶段
body 是 awk 真正工作的阶段
END 是最后处理阶段。

案例: 输出test.txt中的每一行

[root@itlaoxin41 ~]# awk 'print $0' test.txt
cccc
old new old now 

在这个案例中: awk每次读取一行
具体的执行过程:

  • 读取文件第一行 (awk 默认按行读取文件)
  • 将所读取的行赋值给 awk 的变量 $0,于是 $0 中保存的就是本次所读取的行数据
  • 进入代码块 print $0 并执行其中代码 print $0,即输出 $0,也即输出当前所读取的行
  • 执行完本次代码之后,进入下一轮 awk 循环:继续读取下一行 (第二行)


全部读取完成后,退出awk

记录和域

域标记: awk执行时,其浏览标记为$1, 2... 2... 2...n,这种方法称为域标记

$1 表示参照第一域, 多个域用,分割,比如$1,$3
$0 表示所有域

内置变量:

···

NR:表示当前的行数;
NF:表示当前的列数;
RS:行分隔符,默认是换行;
FS:列分隔符,默认是空格和制表符;
OFS:输出列分隔符,用于打印时分割字段,默认为空格
ORS:输出行分隔符,用于打印时分割记录,默认为换行符

案例:

以冒号为分隔符,打印第三个域

[root@itlaoxin41 ~]# awk -F ":" 'print $3' /etc/passwd

假设我们想截取多列,比如:

截取用户名,用户ID,家目录和bash

[root@itlaoxin41 ~]# awk -F ":" 'print $1,$3,$6,$7' /etc/passwd
root 0 /root /bin/bash

这里需要知道,awk默认以空格为分隔符

内建变量的用法

1. FS

指定列分隔符
···

[root@itlaoxin41 ~]# echo "111|222|333" |awk 'print $1'
111|222|333
[root@itlaoxin41 ~]# echo "111|222|333" |awk 'BEGINFS="|"print $1'
111
[root@itlaoxin41 ~]# 

2. OFS

输出列分隔符,用于打印时分割字段,默认为空格

[root@itlaoxin41 ~]# echo "111 222 333" |awk 'BEGINOFS="/"print $1,$2'
111/222
[root@itlaoxin41 ~]# echo "111 222 333" |awk 'BEGINOFS="/"print $1,$2,$3'
111/222/333
[root@itlaoxin41 ~]# 

3.RS

行分隔符,默认是换行符;

[root@itlaoxin41 ~]# echo "111 |222|333|444" |awk 'BEGINRS="|"print $0'
111 
222
333
444

4. ORS

ORS指定输出行分隔符

[root@itlaoxin41 ~]# echo "111 |222|333|444" |awk 'BEGINRS="|"print $0'>test.sh

[root@itlaoxin41 ~]# cat test.sh
111 
222
333
444

[root@itlaoxin41 ~]# awk 'BEGINORS="|";print $0' test.sh
111 |222|333|444||

5. NF

当前的列数

[root@itlaoxin41 ~]# cat test.sh 
111 
222
333
444

[root@itlaoxin41 ~]# awk 'print NF' test.sh
1
1
1
1
0

6. NR

当前行的行数

[root@itlaoxin41 ~]# cat test.sh 
111 
222
333
444

[root@itlaoxin41 ~]# awk 'print NR' test.sh
1
2
3
4
5

BEGIN 和END语句块

awk程序由三部分组成,分别为

初始化:处理输入前做的准备,放在BEGIN块中。
数据处理:处理输入数据。

收尾处理:处理输入完成后要进行的处理,放到END块中。

其中,在“数据处理”过程中,指令被写成一系列模式/动作过程,模式是用于测试输入行的规则,以此确定是否将应用于这些输入行。

awk 的所有代码 都是写在语句块中的

root@itlaoxin41 ~]# awk -F ":" 'print $1' passwd |head -3
root
ceshi
no such person

语句块可分为 3 类: BEGIN语句块, END语句块,和main语句块

其中 BEGIN 语句块和 END 语句块都是的格式分别为 BEGIN… 和 END…

main 语句块是一种统称,它的 pattern 部分没有固定格式,也可以省略,main 代码块是在读取文件的每一行的时候都执行的代码块。

且:
BEGIN代码块:

  • 在读取文件之前执行,且执行一次
  • 在BEGIN代码块中,无法使用 $0 或者其他变量

main 代码块:

  • 读取文件时循环执行,(默认情况) 每读取一行,就执行一次 main 代码块
  • main 代码块可有多个

END代码块

  • 在读取文件完成之后执行,且执行一次
  • 有 END 代码块,必有要读取的数据 (可以是标准输入)
  • END 代码块中可以使用 $0 等一些特殊变量,只不过这些特殊变量保存的是最后一轮 awk 循环的数据

常见案例

1. 使用NR行号提取ip

[root@itlaoxin41 ~]# ifconfig |grep inet |awk 'NR==1print $2'
192.168.1.41

2. 打印UID小于10的账号名称和UID信息

[root@itlaoxin41 ~]# awk -F : '$3 < 10print $1,$3' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8

3. 数学运算

加法:awk ‘a=1; b=2; print a+b’
减法:awk ‘a=1; b=2; print a-b’
乘法:awk ‘a=1; b=2; print a*b’
除法:awk ‘a=1; b=2; print a/b’
取余:awk ‘a=1; b=2; print a%b

4. AWK打印硬盘设备名称,默认以空格为分割:

df -h|awk 'print $1'     $1 第一列

5. AWK以空格、冒号、\\t(Tab缩进) 、分号为分割显示第4列内容:

awk -F '[ :\\t; ]' 'print $4' test.txt

6. AWK以冒号分割,打印第一列,同时将内容追加到/tmp/awk.log下:

awk -F: 'print $1 >>"/tmp/awk.log"' test.txt

7. 打印test.txt文件中的第3行至第5行(2种写法):NR表示打印行,$0表示文本所有域:

awk 'NR==3,NR==5 print' test.txt
awk 'NR==3,NR==5 print $0' test.txt

8. 打印test.txt文件中的第3行至第5行的第一列与最后一列:

awk 'NR==3,NR==5 print $1,$NF' test.txt

备注:默认情况下,awk操作的文本以空格或者缩进格(Tab)为列的分界序列

9. 打印test.txt文件中,长度大于80的行号:

awk 'length($0)>80 print NR' test.txt

10. AWK引用Shell变量,使用-v或者双引号+单引号即可:

`awk -v STR=hello 'print STR,$NF' test.txt`  

 #test.txt每行前加入hello打印
STR="hello";echo|awk 'print "'$STR'";'      #需要订正!

总结

AWK没有一万字写不完,这刚刚开始就干到了4500字, 足够你学习用了。

以上是关于shell脚本四剑客之awk详解的主要内容,如果未能解决你的问题,请参考以下文章

shell三剑客之awk详解

shell 编程四剑客简介 find sed grep awk(微信公众号摘抄)

shell脚本之grep的使用方法

shell脚本江湖秘籍只传有缘人——流编辑器“三剑客”之awk命令

shell命令三剑客之awk命令详解,cut命令,linux里记录行踪(操作记录)

linux12shell编程 --> 三剑客之awk命令