1. 总览
grep
、sed
和awk
被称为Linux三剑客,是因为它们在文本处理和数据操作方面极其强大且常用。
Linux三剑客在文件处理中的作用:
grep(数据查找定位):文本搜索工具,在文件中搜索符合正则表达式的文本内容,并打印匹配的行。
awk(数据切片):文本处理工具,主要用于对结构化数据进行格式化和拆分处理,进行数据统计和报告生成;
sed(数据修改):流编辑器,对文本进行插入、删除、替换、提取等操作;
2. grep
grep
是一个用于文本搜索的工具,可以在文件中搜索符合正则表达式的文本内容,并打印匹配的行。它简单、快速,是进行文本搜索和过滤的首选工具。
grep工具的功能:
文本模式搜索
正则表达式匹配
高亮显示匹配内容
支持递归搜索目录
2.1 基本格式
grep [选项参数] pattern [file...]
参数说明:
1)pattern:过滤条件,可以是正则表达式;
2)file:要搜索的文件(一个或多个),若不指定文件,grep
会从标准输入读取。
3)常用选项参数:
参数 | 说明 |
---|---|
-i | 不区分大小写 |
-v | 排除匹配结果 |
-r 或 -R | 递归搜索目录下的所有文件 |
-l | 仅显示包含匹配模式的文件名 |
-L | 仅显示不包含匹配模式的文件名 |
-n | 显示匹配行与行号 |
-c | 只统计匹配的行数 |
-o | 只输出匹配到的内容 |
-w | 只匹配过滤到的单词 |
-A num | 显示匹配行及之后的 num 行 |
-B num | 显示匹配行及之前的 num 行 |
-C num | 显示匹配行及前后各 num 行 |
-E | 使用扩展正则表达式(等同于 egrep ) |
-F | 使用固定字符串模式(等同于 fgrep ) |
-P | 使用 Perl 正则表达式 |
4)grep中正则表达式字符集整理:
-
普通字符:匹配自身。例如,
grep 'a' file.txt
匹配文件中所有包含字符a
的行。 -
点(.):匹配任意单个字符(除换行符外)。例如,
grep 'a.c' file.txt
匹配a
和c
之间有一个字符的行。 - 字符集([...]):
-
[abc]:匹配字符
a
、b
或c
中的任意一个。 -
[^abc]:匹配除
a
、b
和c
之外的任意字符。 -
[a-z]:匹配从
a
到z
的任意字符(包括范围内的字符)。
-
- 锚点(^ 和 $):
-
^:匹配行首。例如,
grep '^a' file.txt
匹配以a
开头的行。 -
$:匹配行尾。例如,
grep 'a$' file.txt
匹配以a
结尾的行。
-
-
转义字符(\):用来转义元字符,使其失去特殊含义。例如,
grep '\.' file.txt
匹配包含.
字符的行
扩展正则表达式字符集(使用 grep -E
或 egrep
):
-
|:逻辑或,匹配左右任意一个表达式。例如,
grep -E 'a|b' file.txt
匹配包含a
或b
的行 -
():用于分组。例如,
grep -E '(abc|def)' file.txt
匹配包含abc
或def
的行。 -
?:匹配前面的字符 0 次或 1 次。例如,
grep -E 'colou?r' file.txt
匹配color
或colour
。 -
*:匹配前面的字符 0 次或多次。例如,
grep -E 'ab*c' file.txt
匹配ac
、abc
、abbc
等 -
+:匹配前面的字符 1 次或多次。例如,
grep -E 'ab+c' file.txt
匹配abc
、abbc
等。 -
{}:{n}表示匹配前面的字符恰好 n 次;{n,}表示匹配前面的字符至少 n 次;{n,m}表示匹配前面的字符至少 n 次,至多 m 次。
2.2 常用命令举例
假设有一个file.txt文件,内容如下:
name,age,sex,salary
Alice,30,女,9000
Bob,25,男,8000
Carol,35,男,7000
Karry,21,女,5000
Ross,40,女,6500
Joan,38,男,10000
Linda,46,女,5000
Lily,26,女,3000
KARRY,27,女,6000
1. 基本搜索
# 搜索文件 file.txt 中包含 karry 的行
grep "Karry" file.txt
2. 忽略大小写
# 搜索文件 file.txt 中包含 karry(不区分大小写)的行。
grep -i "karry" file.txt
3. 递归搜索目录
# 递归搜索目录 /path/to/directory 中所有文件,查找包含 pattern 的行
grep -r "Karry" /opt/
4. 显示匹配行号
# 搜索文件 file.txt 中包含 karry 的行,并显示匹配行号
grep -n "Karry" file.txt
5. 仅显示匹配文件名
# 搜索当前目录下所有 `.txt` 文件,显示包含 `pattern` 的文件名。
grep -l "Karry" *.txt
6. 反向匹配
# 搜索文件 `file.txt` 中不包含 `pattern` 的行。
grep -v "Karry" file.txt
7. 显示匹配行及之后的行
# 搜索文件 `file.txt` 中包含 `pattern` 的行,并显示匹配行及之后的 3 行。
grep -A 3 "Karry" file.txt
8. 显示匹配行及之前的行
# 搜索文件 `file.txt` 中包含 `pattern` 的行,并显示匹配行及之前的 3 行
grep -B 3 "Karry" file.txt
9. 显示匹配行及前后行
# 搜索文件 `file.txt` 中包含 `pattern` 的行,并显示匹配行及前后各 3 行。
grep -C 3 "Karry" file.txt
10. 使用扩展正则表达式
# 搜索文件 `file.txt` 中包含 `Ka` 或 `Bo` 的行。
grep -E "Ka|Bo" file.txt
11. 匹配整个单词
# 搜索文件 `file.txt` 中包含整个单词 `word` 的行。
grep -w "Karry" file.txt
12. 仅显示匹配的部分
# 搜索文件 `file.txt` 中的 `Karry` 并仅显示匹配的部分。
grep -o "Karry" file.txt
3. awk
awk
是一个强大的文本处理工具,主要用于对结构化数据进行模式扫描和处理,有着强大的文本格式化能力。它支持复杂的操作和脚本编写,能够进行模式匹配、文本处理、数据报告生成等。
awk功能:
字符串处理和替换;
数据统计和报告生成;
复杂的条件判断和循环处理;
数据格式转换。
3.1 基本格式
awk [选项参数] 'pattern { action }' file
参数说明:
1)pattern
:匹配的模式,支持正则表达式。
2)action
:在匹配模式的行上执行的操作。
3)常用选项参数:
参数 | 说明 |
---|---|
-F fs | 指定输入字段分隔符,默认是空格或制表符 |
-v var=value | 为awk 程序中的变量赋初值 |
-f program-file | 从指定文件读取awk 程序 |
4)常见的内置变量
内置变量 | 说明 |
---|---|
$0 | 表示完整的输入记录 |
$n | 表示指定分隔符后,当前指定的第n个字段 |
FS | 表示字段输入分隔符,默认以空格为分隔符 |
OFS | 表示字段输出分隔符 |
NF | 表示字段的个数,即以分隔符分割后,当前行一共有多少个字段 |
NR | 表示当前记录数,即行数 |
3.2 常用命令举例
假设有一个file.txt文件,内容如下:
name,age,sex,salary
Alice,30,女,9000
Bob,25,男,8000
Carol,35,男,7000
Karry,21,女,5000
1.基本示例
# 打印文件file.txt的每一行
awk '{ print }' file.txt
2.指定字段分隔符
假设文件内容用逗号分隔,打印第1、第3个字段。(其中 -F ',' 可以直接简写成-F,)
awk -F ',' '{ print $1, $3 }' file.txt
3.使用模式匹配
# 打印包含“Karry”字符串的行
awk '/Karry/ { print }' file.txt
4.按条件过滤
# 打印第2列字段(age)大于30的人的姓名
awk -F ',' '$2 > 30 { print $1 }' file.txt
5.使用变量
# 为变量age赋值并使用
awk -F ',' -v age=30 '$2 > age { print $0 }' file.txt
6.BEGIN和END块
BEGIN
块在处理任何输入行之前执行。
END
块在处理完所有输入行后执行。
# 计算file.txt文件中第4列字段(工资)的总和
awk -F ',' 'BEGIN { sum=0 } { sum += $4 } END { print sum }' file.txt
7.使用-f
选项从脚本文件中读取程序
1)创建一个名为script.awk
脚本文件
vim script.awk
并将以下内容写入脚本文件中:
#!/usr/bin/awk -f
# 使用逗号作为字段分隔符
BEGIN { FS = "," }
# 打印第1和第3字段
{ print $1, $3 }
详细说明:
脚本文件头部:
#!/usr/bin/awk -f
指定用awk
解释器来运行这个脚本文件。BEGIN 块:
BEGIN { FS = "," }
设置字段分隔符为逗号(,
)。主代码块:
{ print $1, $3 }
打印每行的第1和第3字段。
保存文件并关闭编辑器 :wq!
2)运行awk脚本文件(有两种方式) 方式一:直接用 awk
命令来执行这个脚本
awk -f script.awk file.txt
方式二:授权脚本文件具有可执行权限,然后运行脚本文件
# 确保脚本文件具有可执行权限:
chmod +x script.awk
#运行脚本文件,并指定输入文件:
./script.awk file.txt
8. 格式转换
# 将file.txt文件格式转换为TSV(Tab Separated Values)格式
awk 'BEGIN { FS=","; OFS="\t" } { $1=$1; print }' file.txt
说明:
BEGIN { FS=","; OFS="\t" }
:在处理开始时,将输入字段分隔符设置为逗号,将输出字段分隔符设置为制表符。
$1=$1; print
:通过赋值操作强制awk
重新解析字段,然后输出。
9.提取并格式化指定列
# 假设想提取 `Name` 和 `Age` 列,并格式化输出为 "Name: Age years old"
awk -F ',' '{ print "Name: " $1 ", Age: " $2 " years old" }' file.txt
10.转换为JSON格式
将file.txt文件转换为JSON格式:
awk -F, 'NR==1 {
for (i=1; i<=NF; i++) header[i]=$i;
next
} {
printf("{");
for (i=1; i<=NF; i++) {
printf("\"%s\":\"%s\"", header[i], $i);
if (i<NF) printf(", ");
}
printf("}\n");
}' file.txt
11.转换为HTML表格
将file.txt转换为HTML表格:
awk -F, 'BEGIN {
print "<table border=\"1\">";
print "<tr><th>Name</th><th>Age</th><th>Gender</th></tr>";
}
NR>1 {
printf("<tr>");
for (i=1; i<=NF; i++) printf("<td>%s</td>", $i);
printf("</tr>\n");
}
END {
print "</table>"
}' file.txt
4. sed
sed
是一个流编辑器,主要用于对文本进行非交互式编辑。它可以进行插入、删除、替换、提取等操作,是文本处理和转换的利器。
功能:
文本替换和删除;
模式匹配和文本插入;
支持脚本编写进行复杂的文本处理;
数据流操作。
4.1 基本格式
sed [选项参数] 'script' [file]
参数说明:
1)script:sed 内置的命令字符。主要是用于对文件进行增删改查等操作。
常见内置命令字符:
a:表示对文本进行追加操作,在指定行后面添加一行或多行文本;
d:表示删除匹配行;
i:表示插入文本,在指定行前添加一行或多行文本;
p:表示打印匹配行内容,通常与-n一同使用;
s/正则/替换内容/g:表示匹配正则内容,然后替换内容(支持正则表达式),结尾g表示全局匹配;
2)file:要处理的输入文件。若不指定文件,sed
会从标准输入读取。
3)常用选项参数:
常见选项参数 | 说明 |
---|---|
-n | 表示取消默认的sed输出,通常与sed内置命令p一起使用 |
-e script | 直接在命令行上添加要执行的sed 脚本 |
-f script-file | 从脚本文件中读取sed 命令 |
-i [SUFFIX] | 直接修改文件内容,而不是输出到标准输出。可以选择性地备份文件。如果不加-i,sed修改的是内存数据。 |
-r | 使用扩展正则表达式 |
s | 将文件视为独立的文件,而不是单一的流 |
4.2 常用命令举例
假设有一个file.txt文件,内容如下:
name,age,sex,salary
Alice,30,女,9000
Karry,21,女,5000
Joan,38,男,10000
Lily,26,女,3000
KARRY,27,女,6000
1. 文本替换
# 基本替换:将`file.txt`中的第一个匹配`Karry`的字符串替换为`Bob`
sed 's/Karry/Bob/' file.txt
# 忽略大小写替换:将`file.txt`中的所有匹配`Karry`的字符串替换为`Bob`
sed 's/Karry/Bob/Ig' file.txt
# 全局替换:将`file.txt`中的所有匹配`Lily`的字符串替换为`karry`
sed 's/Lily/karry/g' file.txt
# 指定行替换:将`file.txt`中的第4行中匹配`Joan`的字符串替换为`Carol`
sed '4s/Joan/Carol/' file.txt
# 行号范围替换:将`file.txt`中的第3到第6行中匹配`KARRY`的字符串替换为`karry`
sed '3,6s/KARRY/karry/Ig' file.txt
使用 sed
进行文本替换时,默认情况下,sed
只是将替换后的文本输出到标准输出(通常是终端),而不会直接修改源文件。只有使用-i
参数进行替换,会修改源文件。
# 替换源文件内容:直接在`file.txt`中替换所有匹配`Karry`的字符串为`Bob`,并保存修改(修改源文件)
sed -i 's/Karry/Bob/g' file.txt
#备份原始文件,使用`-i`参数加上备份扩展名来实现,进行替换操作之前会创建一个`file.txt.bak`备份文件
sed -i.bak 's/Karry/Bob/g' file.txt
2. 文本删除
# 删除某行:删除`file.txt`中的第5行
sed '3d' file.txt
# 行号范围删除:删除`file.txt`中的第2到第4行。
sed '3,4d' file.txt
3. 文本插入
# 插入行:在`file.txt`中的第2行之前插入`This is a new line.`
sed '2i\This is a new line.' file.txt
# 追加行:在`file.txt`中的第3行之后追加`This is a new line.`
sed '3a\This is a new line.' file.txt
4. 打印模糊匹配行
# 只打印`file.txt`中包含`ka`的行
sed -n '/ka/p' file.txt
5. 从文件读取脚本
1)创建一个 sed
脚本文件
vim `script.sed`
并将以下内容写入脚本文件中:
3a\
This is a new line.
2)使用 sed
执行脚本文件 使用 sed
命令并指定 -f
选项来读取和执行 script.sed
文件中的命令:
sed -f script.sed file.txt
5. 与管道结合使用
Linux三剑客grep
、awk
和sed
是文本处理的强大工具,经常与管道( | )结合使用,能进行复杂的文本操作和数据处理。用管道符( | )连接,表示将前一个命令的输出作为下一个命令的输入。
假设有一个日志文件file.log
,内容如下:
2023-06-25 12:34:56 info User1 logged in
# 连接数据库失败
2023-06-25 12:35:00 error Failed to connect to database
2023-06-25 12:35:05 info User2 logged out
2023-06-25 12:36:10 warn Disk space low
2023-06-25 12:36:15 info User3 logged in
2023-06-25 12:37:00 error Time out
5.1 查找并替换文件中的文本
使用 grep
查找特定的文本行,用 sed
替换:
# 查找包含 `error` 的行并将 `error` 替换为 `warning`
grep 'error' file.log | sed 's/error/warning/g'
5.2 统计日志文件中特定模式的出现次数
使用 grep
查找特定模式,然后用 wc
统计行数:
# 统计 `file.log` 中 `error` 的出现次数:
grep 'error' file.log | wc -l
5.3 过滤空行和注释行后显示文件内容
使用 grep
和 sed
去除空行和注释行:
grep -v '^#' file.log | sed '/^$/d'
命令拆解:
1)
grep -v '^#' file.log
:grep用于文件中搜索匹配行;-v
表示反转匹配,即选出不匹配指定模式的行。'^#'
表示匹配以#
开头的行;2)
sed '/^$/d'
:sed用于逐行处理文本;/^$/
是正则表达式,匹配空行(行首紧跟行尾,即行中没有任何字符);d
表示删除命令,表示删除匹配的行。
5.4 组合命令过滤并格式化输出
使用 grep
过滤日志,awk
格式化输出:
# 从日志文件中提取 `ERROR` 行,并显示时间和错误信息:
grep 'error' file.log | awk '{print $1, $2, $3, $5}'
5.5 对文件中的数值列进行排序和去重
使用 awk
提取数值列,sort
排序,uniq
去重:
awk '{print $2}' file.log | sort -n | uniq
命令拆解:
1)
awk '{print $2}' file.log
:打印 file.log 文件每行的第2个字段,awk默认是空格或制表符作为分隔符;2)
sort -n
:将上一步输出的数据按数值排序。sort命令用于对文本行进行排序,-n
选项表示按数值进行排序。3)
uniq
: 移除相邻的重复行,输出唯一的行。只有在相邻行重复时,uniq
才会去重,因此通常与sort
结合使用。
5.6 统计日志文件中每种日志级的出现次数
awk '{count[$3]++} END {for (level in count) print level, count[level]}' file.log
命令解析:
1)
{count[$3]++}
:awk的主处理块,在读取文件的每一行时执行,遇到相同的第三列值时,对应的计数器
count[$3]` 自增 1。2)
END {for (level in count) print level, count[level]}
:awk
的结束块,在处理完所有行后执行。for循环遍历count
数组中的所有键,打印每个键(即第三列的值)及其对应的计数器值(即出现次数)。
5.7 grep、awk、sed三者结合使用
筛选日志文件 file.log
中包含"error"的行,并从中提取出时间戳和错误信息,然后进行一些格式化处理:
grep "ERROR" log.txt | awk '{print $1, $2, $5}' | sed 's/\[//g; s/\]//g'
命令解析:
grep "ERROR" log.txt
:筛选出包含 "ERROR" 的行。
awk '{print $1, $2, $5}'
:提取每行的第1列、第2列和第5列。
sed 's/\[//g; s/\]//g'
:删除方括号。
5.8 多文件操作
将多个文件内容合并后进行处理:
cat file.log file.txt | grep 'error' | sort | uniq