Ubuntu小技巧15--awk命令详解
Ubuntu小技巧15–awk命令详解
1 基本介绍
Awk是一种用于处理数据和生成报告的UNIX编程语言。 Nawk是awk的较新版本,而gawk是Linux上使用的GNU版本。awk 的数据可以来自标准输入、一个或多个文件,也可以来自一个程序的输出。 其既可以在命令行上进行一些简单的操作,也可以将Awk写入到大型应用程序中。 由于awk可以处理数据,所以它是在shell脚本和管理小型数据库中必不可少的工具。 Awk从第一行到最后一行逐行扫描文件(或输入),搜索与指定模式匹配的行,并在这些行上执行选定的操作(用大括号括起来)。 如果存在没有特定操作的模式,则显示所有与该模式匹配的行;否则,将显示所有行。 如果存在没有特定模式的动作,则所有输入行多会被执行。
1.1 工作原理
测试文件:names
案例: awk ‘{print $1,$3}’ names
结果:
- awk 从文件或者管道获取第一行作为输入信息,将其保存到内部变量$1中;默认,每一行都会保存为一个临时记录;如下图所示:
- awk 通过空格或者tab键将该行($0)拆分为多个区域(单词),每个区域都会存放到一个单独的内部变量中,依次从$1, $2, $3 … $n存储,最多可以存储100个变量。第一行存储如下:
- awk内部有一个变量FS(field separator),它用于区分不同区域,FS默认为空格-tab键,即:默认通过空格和tab键隔离不同的区域;如果需要通过其它字符来隔离不同区域|单词,也可以修改FS的值。
- 将$0拆分后,通过print函数输出对应的值(实际中可以根据需要对数据进行处理输出),此处直接输出第1,3两个变量。
{print $1,$3}
如果两个变量之间使用’,’ 则输出之间会自动产生一个空格,如果没有’,‘则输出直接相连;
此处$1和$3之间的’,‘映射到一个特殊的内部变量OFS(output field separator ), 其默认赋值为一个空格,因此添加’,'后输出自带空格。 - 当awk完成改行的输出后,其将再次获取下一行,并使用上述1-4的步骤进行处理;如此循环,直到最后一行被处理完。
1.2 使用格式
awk的使用格式如下:
awk ‘pattern’ filename
awk ‘{action}’ filename
awk ‘pattern {action}’ filename
案例1.2.1:
$date>date.txt
$cat date.txt
2020年 02月 16日 星期日 22:46:25 CST
$ cat date.txt|nawk ‘{ print "Month: " $2 "\nYear: " , $1 }’
结果:
案例1.2.2:
数据employees
结果:
2 常用功能介绍
2.1 格式化输出
- print 函数
案例2.1.1:date| awk ‘{ print "Month: " $2 "\nYear: " , $1 }’
说明:输出月份和年
案例2.1.2:awk ‘/Sally/{print "\t\tHave a nice day, " $1, $2 “!”}’ employees
说明:匹配Sally开始的行,输出: Have nice day,Sally Chang - OFMT变量
OFMT变量用于控制输出的数字格式, 该功能也可以通过printf来实现.
案例2.1.3:awk ‘BEGIN{OFMT="%.2f"; print 1.2456789, 12E-2}’
说明:用于控制数字输出格式,小数点后2位
结果: 1.25 0.12 - printf 函数
该函数让用户可以按照指定格式对内容进行输出,类似于c语言中的printf 函数;
其可用转化字符包括:
|转换字符 |定义 |
|–|--|
| c | 字符 |
| s | 字符串 |
| d | 十进制 |
| ld | 长整形十进制 |
| u | 无符号十进制|
| lu | 长整形无符号十进制 |
| x | 十六进制 |
| lx | 长十六进制 |
| o | 八进制 |
| lo | 长八进制 |
| e | 使用科学计数法的浮点数 |
| f | 浮点数 |
| g | 浮点数,使用e后者f类型(自动占用最少空间) |
其可用修饰器包括:
| 字符 | 定义 |
|–|--|
| - | 左对齐 |
| # | 八进制整数起始为一个0,十六进制整数起始为0x |
| + | 对于转移字符为d,e,f,g的整数, 会显示其+或者- 符号 |
| 0 | 显示的值填充为0,而非空格 |
案例2.1.4 : echo “UNIX” | awk ’ {printf “|%-15s|\n”, $1}’
说明: 输出UNIX,且左对齐占用15个字符,默认补充为空格,若无-则为右对齐;
结果: |UNIX |
案例2.1.5: awk ‘{printf “The name is: %-15s ID is %8d\n”, $1, $3}’ employees
说明: 输出The name is: xx(占用15个字符,左对齐) ID is yy(占用8位切右对齐)
结果:
2.2 从文件获取awk命令
将awk命令写入文件中,通过-f导入命令,然后执行;若文件中由多个处理规则|方法,则每个行数据都会被这些规则处理,然后输出.
假设存在 awkfile 文件,包含2行内容,
案例2.2.1 : awk -f awkfile employees
说明: 对每一行数据,先匹配是否一Mary开头,是则输出Hello Mary; 并输出第1-3个单词;
结果:
除此之外,若有多个 匹配模式和行为,则可以将这些内容逐行写到脚本文件中,然后通过-f导入. 脚本中可以使用#来注释不需要的内容.
假如由info脚本文件,内容如下:
第1,2,6为注释内容,3,4,5为对的awk模式和行为, NR标志当前为第几行.
案例2.2.2: awk -f info employees
说明: 对每一行,分别用3,4,5对应的规则进行匹配,匹配到则执行对应的行为.
结果:
2.3 模式和动作
- 模式
awk中的模式可以为正则表达式,或者一个条件表达式, awk的每行会对使用模式进行判断,符合要求则输出.
案例 2.3.1: awk ‘/Tom/’ employees
说明: 匹配到Tom则输出改行,等价于 awk ‘$0 ~ /Tom/{print $0}’ employees
结果: Tom Jones 4424 5/12/66 543354
注意: 等价表达中~ 为匹配符, 即从$0中匹配正则表达/Tom/
案例2.3.2: awk ‘$3 < 4 000’ employees
说明: 匹配到$3小鱼4000的行,并输出
结果:
- 动作
awk中动作为{}包围的语句, 动作既可以由模式触发,又可以单独使用, 还可以多个动作同时使用(多个动作之间使用;隔开). 其格式为 {action}
案例2.3.3: date | awk ‘{print $1, $2, $3}’
说明: 输出 年 月 日
案例2.3.4: date | awk ‘{print $1; print $2}’
说明: 2个动作,分行输出 年 月; 等价于 date | awk ‘{print $1};{print $2}’
案例2.3.5: awk ‘/Tom/ {print “hi tom!”}’ employees
说明: 匹配到Tom后才执行动作,输出hi tom!
2.4 正则表达
awk的模式中支持正则表达式, 基本用法大致同grep的正则表达类似; 若某一行输入被正则匹配到,则会执行正则对应的行为; 若正则后没有对应的行为,则直接输出匹配的行.
以下为awk支持的正则标志和作用:
Metacharacter | What it does |
^ | 从字符串起始开始匹配 |
$ | 从字符串结尾开始匹配 |
. | 匹配一个字符 |
* | 匹配0或者多个之前的字符 |
+ | 匹配至少1个之前的字符 |
? | 匹配0这这1个之前的字符 |
[ABC] | 匹配任何一个在集合中的字符 |
[ABC] | 匹配任何一个不在集合中的字符 |
[A-Z] | 匹配任何一个在A-Z 范围的字符 |
A|B | 匹配A或者B |
(AB)+ | 匹配至少1个集合AB例如AB,ABAB,ABABAB等 |
\* | 匹配字符 * 符号 |
& | 用于保存搜索的字符串, 多配合替换功能 |
注: awk 不支持: \< >/ , \( \) , \{ \} 等3种正则用法;
案例2.4.1: awk ‘/Mary/’ employees
说明: 输出包含Mary的行
案例2.4.2: awk ‘/^[A-M][a-z]+ /’ employees
说明: 匹配 以大写A-M之间字符开头,紧接着至少1个小写字母,随后一个空格 的行
结果:
3 经典案例
- 文本信息打印
打印文件的第一列(域) : awk ‘{print $1}’ filename
打印文件的前两列(域) : awk ‘{print $1,$2}’ filename
打印完第一列,然后打印第二列 : awk ‘{print $1 $2}’ filename
打印文本文件的总行数 : awk ‘END{print NR}’ filename
打印文本第一行 :awk ‘NR==1{print}’ filename
打印文本第二行第一列 :sed -n “2, 1p” filename | awk ‘print $1’ - 进程信息处理
关闭wps相关所有进程:ps -ef|grep wps|awk ‘{print $2}’|xargs kill - awk练习题
数据源 data.txt 内容如下:
- 1 通过第一个域找出字符长度为4的
2 当第二列值大于3时,创建空白文件,文件名为当前行第一个域$1 (touch $1)
3 将文档中 liu 字符串替换为 hong
4 求第二列的和
5 求第二列的平均值
6 求第二列中的最大值
7 将第一列过滤重复后,列出每一项,每一项的出现次数,每一项的大小总和
1、字符串长度
awk ‘length($1)==“4”{print $1}’
2、执行系统命令
awk ‘{if($2>3){system ("touch "$1)}}’
3、gsub(/r/,“s”,域) 在指定域(默认$0)中用s替代r (sed ‘s///g’)
awk ‘{gsub(/liu/,“hong”,$1);print $0}’ a.txt
4、列求和
df -h | awk ‘{a+=$2}END{print a}’
5、列求平均值
df -h | awk ‘{a+=$2}END{print a/NR}’
df -h | awk ‘{a+=$2;b++}END{print a,a/b}’
6、列求最大值
df -h | awk ‘BEGIN{a=0}{if($2>a) a=$2 }END{print a}’
7、将第一列过滤重复列出每一项,每一项的出现次数,每一项的大小总和
awk ‘{a[$1]++;b[$1]+=$2}END{for(i in a){print i,a[i],b[i]}}’ - 使用特定区域分隔符
案例: cho ‘Tom Jones:4424:5/12/66:543354’|awk -F: ‘/Tom Jones/{print $1,$2}’
结果: Tom Jones 4424
说明: -F: 制定分隔符为:, 默认为空格或者tab符. - 匹配操作符(~)
匹配操作符号~, 其作用为: 让一个正则从一条记录或者一个区域中进行匹配.
案例: awk ‘$1 ~ /[Bb]ill/’ employees
说明: 说明, 匹配第一个区域, 包括Bill或者bill , 注意$1 表示只用$1 进行匹配,若该为$0 这用一条记录进行匹配.
结果: Billy Black 1683 9/23/44 336500
4 注意事项
- 后续将在此处增加awk使用中常见的注意事项
5 说明
测试系统版本:Ubuntu 1910 SERVER (64-bit)
参考文献: UNIX® Shells by Example Fourth Edition By Ellie Quigley