Linux 文本三剑客:grep、sed 和 awk

在 Linux 的文本处理领域,sed、awk 和 grep 被誉为“文本三剑客”,它们各自承担着不同的任务,但又相辅相成,成为处理文本文件的强有力工具。在日常开发和系统管理中,掌握这三者能够显著提高工作效率。本文将详细介绍它们的功能、使用方法以及常见的应用场景。 >

1. grep:全局正则表达式打印

1.1 功能概述

grep 是一个文本搜索工具,用于在文件中搜索匹配正则表达式的行,并将匹配到的行输出到标准输出。grep 的名称来源于“g/re/p”——全局正则表达式打印(global / regular expression / print)

1.2 使用方法

基本语法:
1
grep [选项] pattern [文件...]  

1.3 常用选项

  • -i:忽略大小写,比如 grep -i “hello” file.txt。
  • -v:反向匹配,只输出不匹配的行。
  • -r:递归搜索目录及子目录。
  • -n:显示匹配行的行号。
  • -l:只列出匹配的文件名。
  • -c:只输出匹配的行数。
  • -E:使用扩展正则表达式。

1.4 正则表达式基础

  • .:匹配任何单个字符(除了换行符)。
  • *:匹配前面的字符零次或多次。
  • +:匹配前面的字符一次或多次。
  • ?:匹配前面的字符零次或一次。
  • []:匹配括号内的任意一个字符。
  • [^]:匹配不在括号内的任意一个字符。
  • ^:匹配行的开始。
  • $:匹配行的结束。
  • {n,m}:匹配前面的字符至少 n 次,最多 m 次。
  • |:逻辑或,用于匹配多个模式中的任意一个。

1.5 扩展正则和基本正则的区别

  1. 元字符的区别:
    • 在基本正则表达式中,某些元字符(如 ?, +, {, |, (, ))需要使用反斜杠 \ 进行转义才能生效。
    • 在扩展正则表达式中,这些元字符不需要转义,可以直接使用。
  2. 工具支持:
    • 一些工具默认使用基本正则表达式,如 grep。
    • 一些工具提供选项来支持扩展正则表达式,如 grep -E 或 egrep。

1.6 示例

统计data.txt包含“data”的行数:

1
grep -c "data" data.txt  

递归搜索当前目录”TODO”的文件并列出文件名:

1
grep -r -l "TODO" .  

找到 log.txt中所有包含 “error” 并且以 “Failed” 开头的行,忽略大小写

1
grep -i "^Failed.*error" log.txt

1.6.1 区分基本正则和扩展正则的直观例子

找到example.txt中包含 “a” 2 到 4 次的行

  1. 基本正则:
    1
    grep 'a\{2,4\}' example.txt
  2. 扩展正则:
    1
    grep -E 'a{2,4}' example.txt

2. sed:流编辑器

2.1 功能概述

sed 是一个流编辑器,能够对输入文本进行编辑。与 grep 只做查找不同,sed 能够修改文本内容,适合于批量处理文本, 注意: sed操作默认不会改变原文件

2.2 使用方法

基本语法:
1
sed [选项] '命令' [文件...]  

2.3 常用选项

  • -n:抑制默认输出,只输出被处理的行。
  • -e:允许连续使用多個命令。
  • -f:从指定文件中读取命令。
  • -i:在原文件上进行修改,而不是输出到标准输出。
  • -r 或 -E:使用扩展正则表达式(ERE)

2.4 常用命令

  • s/pattern/replacement/:替换模式。
  • d:删除行。
  • p:打印行。
  • i:在指定行之前插入文本。
  • a:在指定行之后追加文本。
  • c:替换指定行的内容。
  • g:全局替换(在同一行中替换所有出现的模式)
  • y: 将字符串中的字符替换为其他字符。

2.5 示例

替换文件中的字符串:

1
2
3
4
5
6
sed 's/foo/bar/g' file.txt

# 于在 file.txt 文件中将所有出现的 "foo" 替换为 "bar"

# /g:表示全局替换,即在同一行中替换所有出现的 "foo",而不仅仅是最先出现的一个

删除包含“debug”的行:

1
2
sed '/debug/d' file.txt  

删除 XX – XX 之间的行

1
2
sed '/start/,/end/d' file.txt
# 删除从包含 "start" 的行到包含 "end" 的行之间的所有行

插入文本:

1
2
sed '2i\This is an inserted line.' file.txt  
# 用于在 file.txt 文件的第 2 行之前插入一行文本

追加文本

1
2
sed '2a\This is an appended line.' file.txt
# 用于在 file.txt 文件的第 2 行之后追加一行文本 "This is an appended line."

使用文件中的命令:

1
2
sed -f commands.sed file.txt  
# 执行存储在 commands.sed 文件中的多个 sed 命令,并将这些命令应用于 file.txt

字符转换

1
2
sed 'y/abc/def/' file.txt
# 将文件中的 'a' 替换为 'd','b' 替换为 'e','c' 替换为 'f'

3. awk:文本处理工具(概述版)

3.1 功能概述

awk 是一种编程语言,用于文本处理与数据提取。其强大的模式匹配和处理能力,使其非常适合格式化文本和报表生成。awk也不会修改原文件,而是输出处理结果到标准输出。

3.2 使用方法

基本语法:
1
awk 'pattern { action }' [文件...]

3.3 常用函数和变量

常用变量

  • $1, $2, …:表示行的字段,字段由分隔符(默认是空格或制表符)分隔。
  • $0:表示整行。
  • NF:表示当前行的字段数。
  • NR:表示当前处理的行号。
  • FILENAME:表示当前处理的文件名。
  • FS:字段分隔符,默认为空格或制表符。
  • OFS:输出字段分隔符,默认为空格。
  • ORS:输出记录分隔符,默认为换行符。
  • RS:记录分隔符,默认为换行符。

常用内置函数

  • print/printf:打印指定的字段或表达式
  • length([string]):返回字符串的长度
  • substr(string, start, [length]):返回子字符串
  • split(string, array, [sep]):将字符串分割成数组
  • gsub(regexp, replacement, [target]):全局替换

3.4 示例

计算字符串的长度

1
2
awk '{ print length($0) }' file.txt
# $0指一整行, 这里是计算文件中每一行的长度

打印特定行号的行和字段

1
2
awk 'NR == 2 { print $1 }' file.txt
# NR是行号, 这里是打印第2行的第一个字段(第一列)

将每行按空格分割成数组并打印

1
awk '{ split($0, words, " "); for (i in words) print words[i] }' file.txt

复杂一点的, 将第二行按空格分割成数组并打印

1
2
3
4
5
6
awk 'NR == 2 {
split($0, words, " ");
for (i in words) {
print words[i];
}
}' file.txt

打印第2行到第3行第一个字段的长度

1
awk 'NR >= 2 && NR <= 3 { print length($1) }' file.txt

将”New York”替换为”NYC”

1
awk '{ gsub(/New York/, "NYC", $0); print }' data.txt

子字符串截取

1
2
awk '{ print substr($0, 2, 5) }' file.txt
# 从 file.txt 文件的每一行中提取从第 2 个字符开始的长度为 5 的子字符串,并打印出来

4. 三剑客结合使用

这三款工具可以结合使用,以处理更复杂的文本处理任务。

  1. 例如,将 grep 和 sed 联合使用,可以先过滤出需要的行,然后在这些行中替换内容:
1
2
grep "error" log.txt | sed 's/error/ERROR/g'  

同样,awk 可以和 grep 配合使用,先筛选行再进行字段提取或处理:

grep "2023" log.txt | awk '{print $5}'

5. 总结

掌握 grep、sed 和 awk 是每个 Linux 用户、系统管理员和开发人员的重要技能。它们各有特长,但在文本处理任务中,能相互配合,形成强大而灵活的解决方案。熟练使用这三款软件,能够让您在处理文本数据时得心应手,提高工作效率。希望本文对您理解和使用 Linux 文本三剑客有所帮助!