精通文本处理:开发者的 Regex、Grep、Sed 与 Awk 指南

发布: (2026年1月5日 GMT+8 04:44)
10 min read
原文: Dev.to

Source: Dev.to

请提供您希望翻译的具体文本内容,我将为您翻译成简体中文,并保留原始的格式、Markdown 语法以及技术术语。谢谢!

介绍:Unix 哲学简述

在现代软件开发中,尽管工具链和 IDE 越来越复杂,朴素的命令行仍然是强大与高效的持久堡垒。能够直接在终端中雕刻、搜索和转换文本并不是一种过时的技能——它是一种永恒的能力,能够将熟练的开发者与真正的大师区分开来。这种力量源自 Unix 哲学:一套小而专精的工具,每个工具都旨在做好一件事。当这些工具串联起来时,便能以优雅且清晰的方式完成复杂任务。

本指南提供了一个实用、动手的文本操作基础工具套件之旅。我们将从正则表达式(regex)——描述文本模式的通用语言——开始。随后,我们将探讨三个将该语言付诸实践的基石工具:grep,终极文件搜索器;sed,闪电般快速的流编辑器;以及 awk,用于结构化数据的强大记录处理器。我们的目标不是穷尽所有细节,而是为你提供处理日常 80 % 文本处理挑战的必备知识。

1. 模式语言:正则表达式(Regex)速成课

在我们能够使用这些工具之前,必须先学习它们的语言。正则表达式是一种用于指定文本搜索模式的形式化语法。不要把它们仅仅看作某个特定程序的功能,而应视为一种可移植的、基础的技能,它能在命令行工具、文本编辑器以及 Python、JavaScript 等编程语言中解锁高级功能。掌握正则表达式的核心概念是一项投资,能在整个职业生涯中带来丰厚回报。

1.1. 核心构件

从本质上讲,正则表达式是一串字符,其中一些是 字面量(匹配自身),另一些是 元字符(具有特殊含义)。最基本的元字符用于控制我们如何匹配单个字符、它们的重复次数以及它们在行中的位置。

下面的示例使用 扩展正则表达式(ERE) 以便更清晰。我们将在 1.3 节中介绍 ERE 与较旧的 基本正则表达式(BRE) 语法之间的关键区别,后者是某些工具的默认语法。

1.2. 指定字符集(字符类)

通常,你并不想匹配任意字符,而是想匹配特定集合中的任意字符。方括号表达式 [...] 是定义这些“字符类”的主要机制。

  • 匹配特定列表 – 列出你想匹配的确切字符。
    示例:[aeiou] 匹配任意单个小写元音字母。

  • 匹配范围 – 两个字符之间的连字符 (-) 会创建一个范围,包含它们之间所有字符(依据系统的排序规则)。
    示例:[a-z] 匹配 ASCII 系统中任意单个小写字母。

注意: 范围的行为高度依赖系统的语言设置(locale)。在 ASCII 中字母是连续的,[a-z] 的行为是可预测的;但在其他语言环境下,字母可能按 a, A, b, B, … 排序。在这种环境中,[a-c] 会意外匹配 a, A, b, B, c,而不是预期的 a, b, c。这是我们将在 POSIX 字符类章节中解决的关键陷阱。

  • 取反集合 – 方括号内部的第一个字符如果是插入符号 (^),则会反转匹配,使其匹配不在该集合中的任意单个字符。
    示例:[^0-9] 匹配任何非数字字符。

1.3. 大分水岭:基本正则 vs. 扩展正则(BRE vs. ERE)

对于刚接触命令行的开发者来说,最常见的困惑点之一是存在两套略有不同的正则语法。这是 Unix 演进过程中的历史遗留。

  • 基本正则表达式(BRE) – 最初、较旧的语法。grepsed 等工具默认使用它。在 BRE 中,许多元字符如 +?|() 会失去特殊含义,必须使用反斜杠 (\) 转义才能激活。

  • 扩展正则表达式(ERE) – 更现代、更易读的语法,特殊字符不需要转义。egrep(或 grep -E)和 awk 等工具使用这种语法。

两者的差异细微却至关重要:

专业提示: 对于任何新脚本,默认使用 grep -Esed -E 的扩展语法。BRE 只是需要了解的历史产物,用于阅读旧脚本;而 ERE 是现代、可读性高的标准。几乎没有充分的理由在新脚本中使用 BRE。

现在我们已经了解了模式语言,让我们看看如何将它与最著名的搭档 grep 一起使用。

2. 使用 grep 在大海捞针

grep(Global Regular Expression Print)是典型的命令行搜索工具。它的目的简单却深远:逐行读取输入,只打印出包含给定模式匹配的行。这使得它在调试代码、分析日志文件以及探索陌生代码库时不可或缺。

2.1. 实际搜索操作

让我们从理论转向实践,看看一些常见的 grep 用例。

示例 1:在日志文件中搜索 IP 地址

要查找特定的 IP 地址,需要对点号进行转义,因为 . 是通配符。使用 \b 表示单词边界可以确保不会匹配到更大数字的子串(例如 101.10.3.20)。

grep '\b1\.10\.3\.20\b' logfile.log

专家提示: 单词边界锚点 \b 是 GNU 的强大扩展,但它 不是 POSIX 标准的一部分,可能并非在所有系统上都可用。真正可移植的方式是显式定义边界——通常是空白字符或行首/行尾。例如,匹配完整单词 “book” 的稳健模式可以写成:

grep '(^|[[:space:]])book([[:space:]]|$)' file.txt

2.2. 反向引用的威力

当你在模式中使用圆括号 (...)(在 BRE 中使用 \(...\))时,会创建一个 捕获组。第 n 个组匹配的文本可以在后面使用 \n 引用。

示例

grep '^\(.*\)\1$' /usr/share/dict/words

可能的输出

adad
beriberi
chichi

另一个经典示例:

egrep -v '^(11+)\1+$'

该命令过滤出用一元表示的素数。

3. 可移植性与国际化:POSIX 字符类

类似 [a-z] 的正则在非 ASCII 区域设置下可能失效。POSIX 字符类通过区域感知的集合来解决此问题,例如:

  • [[:digit:]]
  • [[:alpha:]]
  • [[:space:]]

3.2. 深入比较:[0-9][[:digit:]]\d

模式作用范围
[0-9]仅 ASCII
[[:digit:]]POSIX 可移植(区域感知)
\d仅限 PCRE / Unicode 环境

3.3. 性能秘诀:LC_ALL=C

export LC_ALL=C
grep 'some_pattern' huge_logfile.txt

LC_ALL=C 设置为 ASCII 模式,可显著提升处理速度。

4. 实时转换文本使用 sed

sed 是一种 流编辑器

4.1. 替换语法

s/pattern/replacement/flags
  • &    = 整个匹配
  • \1   = 第一个捕获组
  • g    = 替换所有匹配

4.2. sed 实际使用

常见用法包括:

  • 重排姓名
  • 去除 C++ 注释
  • 为每行加上引号

5. 使用 awk 对数据进行切片和切块

awk 将输入视为 记录和字段

5.1. 模型

pattern { action }

关键变量:

  • $0 — 整行
  • $1 — 第一个字段
  • NF — 字段数量

5.2. 示例:/etc/passwd

awk -F: '$3 > 1000 { print $1 }' /etc/passwd

6. 最终澄清:正则表达式 与 Shell 通配符

  • *.txt 不是 正则表达式;它是 glob 语法,由 shell 用于文件名展开。

结论:您的命令行工具包

  • grep — 搜索
  • sed — 转换
  • awk — 处理结构化数据
Back to Blog

相关文章

阅读更多 »

如何在 Linux 中终止运行的进程

你是否曾经感觉你的 Linux 系统突然不再响应你的操作?你点击、输入、等待……却什么也没有发生。通常这是因为某个进程……

各种 less(1) 技巧

文章 URL: https://blog.thechases.com/posts/assorted-less-tips/ 评论 URL: https://news.ycombinator.com/item?id=46464120 积分: 19 评论: 6

管道

封面图片:Pipes https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com...