awk
使用场景
前面的 grep 和 sed 在处理文本时都是以行为单位,逐行处理;还有很多其他的命令都是以行为单位进行处理。
在实际开发运维中,可能需要拆分整行内容,只关心部分字段。可以使用awk进行拆分,而且awk也支持行数据过滤
简单来说 awk ≈ grep + cut
基本使用
与 grep,sed类似;awk 可以直接从文件获取数据也可以从管道流获取数据
-
基本语法
awk [opts] ‘commands’ file
cat file | awk [opts] ‘commands’ -
opts
常用参数- -F 指定分隔符
- -v 定义一个能在后面脚本中使用的变量,脚本中引用时直接写变量名,无需$,因为awk 脚本内无法直接引用外部变量
awk 内置常用变量:NF(当前行拆分后的列数),NR(行号)
,FILENAME(当前处理的文件名)
-
commands 类型
分为 前置命令BEGIN{},中间命令{},后置命令END{}
前置命令和后置命令只会在处理文件开始和结束时执行依次,而中间命令则会应用到每一行数据,有点类似Junit测试的 @BeforAll @Test @AfterAll 的关系 -
awk 处理文件方式
awk获取到文件内容后,也是一行一行处理,它会以指定分隔符(默认为空格,可通过-F 自定分隔符)将每一行数据拆分成多个字段
$0 代表整行数据,$1…后面依次代表每个字段
awk的功能非常丰富,它作为一门独立的变成语言
- awk 过滤数据
awk 也支持过滤数据;它既支持整行的正则匹配,也支持拆分后的词单项比较或者正则匹配
而且它支持各种比较运算符以及正则表达式(使用 /express/ 匹配拆分后词;使用 ~,取反 !~)
实例
参数使用
- 使用 -F 和 -v
# 以 / 为分隔符,自定义参数 x=123
awk -F / -v x=123 '{print $1, x}'
- 创建 student.txt 文件
编号 姓名 性别 年龄
1 张三 男 11
2 李四 女 9
3 王五 男 17
4 赵六 男 22
5 刘胜男 女 15
6 王小二 男 9
7 张三疯 男 125
- 获取所有学生id
awk '{print $1}' student.txt
编号
1
2
3
4
5
6
7
- 去掉上面的表头
awk '$1 != "编号" {print $1}' student.txt
1
2
3
4
5
6
7
- 查看性别为男的学生信息
awk '$3 == "男"' student.txt
1 张三 男 11
3 王五 男 17
4 赵六 男 22
6 王小二 男 9
7 张三疯 男 125
- 查看性别为男的学生姓名和年龄
awk '$3 == "男" {print $2"\t"$4}' student.txt
张三 11
王五 17
赵六 22
王小二 9
张三疯 125
- 查看姓名以张开头的学生信息
awk '$2 ~ /^张/' student.txt
1 张三 男 11
7 张三疯 男 125
表头被过滤掉了… 加上表头
awk '$2 ~ /^[张(姓名)]/' student.txt
编号 姓名 性别 年龄
1 张三 男 11
7 张三疯 男 125
还可以这样,使用 | 替代 []
awk '$2 ~ /^张|姓名/ ' student.txt
编号 姓名 性别 年龄
1 张三 男 11
7 张三疯 男 125
- 查看姓名不以张开头的学生信息
姓名也不以张开头,直接显示出来了,无需再单独处理
awk '$2 !~ /^张/' student.txt
编号 姓名 性别 年龄
2 李四 女 9
3 王五 男 17
4 赵六 男 22
5 刘胜男 女 15
6 王小二 男 9
- 查找姓张,名只有一个字的学生&带上表头
awk '$2 ~ /^张.$|姓名/' student.txt
编号 姓名 性别 年龄
1 张三 男 11
- 按正则表达式过滤,提取部分字段
awk '$2 ~ /^张.$|姓名/ {OFS="\t"; print $1, $2, $4}' student.txt
编号 姓名 年龄
1 张三 11
awk '$2 ~ /^张.$|姓名/ {print $1"\t"$2"\t"$4}' student.txt
编号 姓名 年龄
1 张三 11
awk '$2 ~ /^张.$|姓名/ {print $1 "\t" $2 "\t" $4}' student.txt
编号 姓名 年龄
1 张三 11
各种匹配方式可结合正则实现
给指定登录当前主机的用户发送消息
#!/bin/bash
# 校验参数
if [[ -z $1 ]]
then
echo "接收用户不能为空"
exit 2
fi
#校验用户是否在线 并且支持消息通讯
login=`who -T | awk -v receive_user=$1 '$1 == receive_user && $2 == "+"'`
if [[ -z login ]]
then
echo "用户当前无法接收消息"
fi
write `echo $login | awk '{print $1 " " $3}'`
cut
功能与awk 类似,都是提取列
常用参数
- -f :取第几列
固定列 用逗号(,)隔开 -f 1,2,3
范围列 用 - 连接,没有边界的那一端不写 - d:分隔符(默认以空格分割,与awk一样)
- c:按字符拆分;取 几个字符 -c 10取前10个字符