likes
comments
collection
share

不可错过的文本处理工具:sed和awk

作者站长头像
站长
· 阅读数 5

大家都说,grep、sed和awk是shell中的文本处理三剑客。他们的功能分别是对文本进行查找、替换和整理输出。

本文会详述awk和sed工具。

awk和sed的整体设计理念

串行流式的使用行缓冲区来处理大文本中的数据。也就是,一行一行的处理文本数据,涉及的概念包括:

  • 文件

awk和sed这些文本处理流工具,可以将输入的流执行打印、转换或者修改等操作。如下示意图:

不可错过的文本处理工具:sed和awk

awk

awk的主要功能是读入文本,做统计报告。

内置变量

首先了解一下awk的内置变量,可分次文件、行和列相关的:

  • 文件相关的变量
    • FNR:表示多文本处理时,每个文件行号单独计数,都是从1开始。
    • FILENAME:当前输入的文件名字。
  • 相关的变量
    • $0:整行内容
    • NRNumber Row 的缩写,表示当前行的行号,从1开始计数。
    • RS -- Row Separator 的缩写,表示输入行分隔符,默认回车换行 \n 。
  • 相关的变量
    • $1-$n: 当前行的第 1-n 个字段。
    • NFNumber Field 的缩写,表示当前行的字段个数,也就是有多少列。
    • FS -- Field Separator 的缩写,表示输入字段分隔符,不指定默认以空格或 tab 键分割。

用法

基本用法是:awk 'BEGIN{...}pattern{...}END{...}' file_name

不可错过的文本处理工具:sed和awk

显示是用print/printf函数,在使用awk的时候用的比较多。

前置处理BEGIN

在处理文本流之前,一般用来初始化变量,比如设置列分隔符FSawk 'BEGIN{FS=":"}'

后置处理END

在处理文本流之后,比如用来打印总和

#  awk 'BEGIN{total=0}{total++}END {print total}' access.log 
495903

access.log 一共有49.59万行。

如何匹配

文本流的行内匹配,awk支持的包括:

  • 通用的Linux正则匹配,文本匹配的格式是/pattern/
##匹配行内有root的行
# awk -F : '/root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

##以root开头的行
operator:x:11:0:operator:/root:/sbin/nologin
# awk -F : '/^root/{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
  • 运算符匹配 awk -F : '$3<10{print $0}' /etc/passwd 满足$3<10,也就是第三列的值小于10,才会print。

awk的一些内置函数

还有一些算术函数、事件函数和字符串函数比如length、substr和index等,需要的时候可以查看用法: www.tutorialspoint.com/awk/awk_bui…

{}中的表达式

前置、后置和流处理块中都可以写入函数表达式,多表达式用;隔开。 变量在awk的三个块中是从BEGIN到流处理、再到END依次传递的,按顺序执行的。

if语法

示意: awk 'BEGIN {num = 10; if (num % 2 == 0) printf "%d is even number.\n", num }'

循环语法

awk 'BEGIN {i = 1; while (i < 6) { print i; ++i } }'

另外还有,都和C语言语法差不多:

  • for循环
  • do while循环
  • break跳出

数组

awk有关联数组, 索引不必是一组连续的数字;可以使用字符串或数字作为数组索引。此外,无需提前声明数组的大小 - 数组可以在运行时增长/缩小。直接使用数组就行,如下:

array_name[index] = value

例子:accesslog统计报告

下面看一个例子。

服务器有一份请求访问的access.log,部分请求是流量攻击,流量攻击有特殊的头部”TEST“,现在要打印流量攻击的不同http请求的统计报告。 我们可以使用awk来做,如下:

# tail access.log
"9.134.77.72" "127.0.0.1" "-" "[11/Jan/2022:21:20:16 +0800]" "/api/test1" "200" "2" "2914" "-" "Prometheus/2.17.1" "TEST"
"9.134.77.72" "127.0.0.1" "-" "[11/Jan/2022:21:20:16 +0800]" "/api/test2" "200" "2" "2914" "-" "Prometheus/2.17.1" "TEST"
...
# grep "TEST" access.log|wc -l # grep可以统计到攻击的调用次数 50万次

## 写awk处理脚本
# cat access.awk 
BEGIN{
       
        FS="\" \"";  
        printf "%-10s %-10s HandledTime ResponseBytes\n", "Request", "Total";
}
## 1、BEGIN设置每行日志列的分隔符是" "(\用来转译);2、打印表头


/TEST/ 
{
        REQUEST[$5]+=1 ;
        REQUEST1[$5]+=$7;# handle time ,ms
        REQUEST2[$5]+=$8; # response bytes;
        handledTime+=$7;
        bytes+=$8;
}
## 匹配有TEST字符串的日志行,$5表示请求的路由,$7表示请求处理时间,$8表示响应的包大小,
##按照路由聚合到REQUEST、REQUEST1和REQUEST2数组,handledTime是总聚合时间,bytes总聚合包大小

END{
    for(u in REQUEST) 
    {
        printf "%-10s %-10d %-10d %-10d\n", u , REQUEST[u], REQUEST1[u], REQUEST2[u]
    }
    printf "handledTime: %d min\n",handledTime/1000/60;
    printf "handledBytes: %d MB\n",bytes/1000/1000;

}
## 遍历数组,打印数组每一项

# awk -f  access.awk  access.log #执行

# #最后输出
api/test1 10000 200000 2000000
api/test2 6900 30000 200000
...
handledTime: 39 min
handledBytes: 960 MB

# #上面的内容保存到文件后,可以使用sort进行排序,找到调用最频繁的请求路由
# sort -k 2 -rn stat.txt |head -n 20

awk总结

通过例子可以看出,sed有一些Option可以配置

  • -F:后面接field的分隔符
  • -f: sed在命令行是通过''输入脚本,也可以-f选择脚本文件。 awk的语法并没有想的那么难,它可以匹配感兴趣的行进行流处理并输出统计报告。

sed工具

前面讲了awk的基本原理和用法,接下来讲讲同样流处理的工具sed。

sed的用法主要是用来修改文本

sed对文本里面的每一行进行匹配,执行一些动作。用法如下: sed [option] '/pattern/command' file

例如:

# sed '/abc/p' test.txt # 省略了option,/abc/为pattern正则匹配,p为command命令打印的意思

主要功能

sed提供了很多命令,包括p打印,d删除和s替换等。

不可错过的文本处理工具:sed和awk

在sed中,最常用的功能是s替换

sed的匹配

匹配是可以按照行号或者字符串\pattern\匹配,如下图:

不可错过的文本处理工具:sed和awk

  • 文本匹配,跟awk的意义,字符串\pattern\匹配,-E 也可以按照增强的正则表达式来匹配
  • 行匹配,数字匹配,比如1p
  • 匹配多行,匹配以start匹配开头的,以end匹配结束的行块。1p,10p可以匹配1-10行。

选项

有一些比较有用的选项:

  • 默认是不修改原文件,而是只将修改的内容输出到控制台。加上选项-i可以原地直接修改文本文件内容
  • 默认会显示匹配并操作的行,选项-n可不显示匹配并操作的行,所以-n和p命令一般配合使用。
  • 选项-e 指令命令处理,可以有多个。sed不像awk可以使用表达式,只能使用简单的命令,但是可以使用多个命令。
  • 选项-f 命令从文件读
  • 选项-E 可以使用增强的正则匹配模式

不可错过的文本处理工具:sed和awk

主要命令

p

#echo hello >>test.txt
#echo "nice to test" >>test.txt
# sed 'p' test.txt # 打印原来的行
hello 
hello
nice to test
nice to test
# sed '2p' -n test.txt
nice to test

2p表示匹配第二行并打印,-n不打印原来的行。

d

# sed  -i '1d' test.txt
# #d不会打印原行   
# cat test.txt                  
nice to test
# sed  '/nice/d' -i test.txt
# cat test.txt
##删完了

d不会打印原行,两次操作之后两行数据都删完了。

s

s的用法是命令放在前头,匹配和替换的字符放后面。语法为s/pattern/replace/

# sed  's/test/hello/' test.txt # 只匹配行的第一个test并替换为hello
hello
nice to hello
# sed  -i 's/test/hello/' test.txt 
# # -i则原地修改不会输出到控制台
#sed  's/test/hello/g' test.txt # g表示要对这一行的所有匹配进行替换
#sed  's/test/hello/2g' test.txt # 
# sed  's/test/hello/1g' test.txt
# sed  's/test/hello/ig' test.txt #忽略大小写

  • s/test/hello/ 只替换行内的第一个,相当于s/test/hello/1g
  • s/test/hello/g 替换行内的所有test为hello
  • s/test/hello/2g,替换行内的匹配到的第二个test到最后的test为hello
  • s/test/hello/ig 匹配忽略大小写,TEST也可以替换

其他不太常用的

其他不太常用的功能还有很多,包括a/i/r/w,可能还有其他的一些,用到的时候可以查查手册。

总结

本文主要讲了awk和sed这两个文本处理流工具的基本原理和常见用法,包括匹配规则,主要命令和基本语法。希望能给你带来一定帮助。