Skip to content

Sed 工作流程

为了有效使用 sed (Stream Editor,流编辑器),理解其内部工作流程至关重要。这些知识是编写高效、可预测的 sed 脚本的基础。sed 按行处理文本,对每一行都遵循一个固定的循环。

sed 工作流程可概括为三个主要步骤,对每行输入重复执行:

  1. 读取 (Read): sed 从输入流(可以是文件、通过管道来自其他命令的输出,或直接的标准输入)读取一行内容到一个临时存储区域,称为 模式空间 (pattern space)。如果是第一行,模式空间初始为空。如果没有更多行可读,sed 停止。
  2. 执行 (Execute): 脚本中提供的所有 sed 命令按顺序应用于模式空间的内容。这些命令可能会修改、删除或向模式空间添加文本。除非使用特定的行寻址(如行号或模式)限制其应用,否则命令默认全局应用于所有行。
  3. 显示 (Display): 在针对模式空间中的当前行执行完脚本中的所有命令后,sed 通常会将(可能已修改过的)模式空间内容打印到标准输出流。可以使用 -n 选项抑制这种默认打印行为。打印后(或被抑制后),与该特定输入行相关的内容通常会从模式空间中清除(除非使用了像 N、D 这样的命令,它们会改变多行处理流程)。

这个读取-执行-显示 (Read-Execute-Display) 循环持续进行,直到处理完输入流中的所有行。

  • 模式空间 (Pattern Space): 这是 sed 的主要工作区。它是一个内存缓冲区,用于存放当前正在处理的行。大多数 sed 命令直接操作模式空间的内容。模式空间的内容是易变的,通常在读取新行时会被替换或清除(高级命令如 N、P、D 除外)。
  • 暂存空间 (Hold Space): sed 还提供了另一个内存缓冲区,称为暂存空间。与模式空间不同,大多数命令不会直接操作暂存空间,其内容也不会自动打印。它的内容在循环之间是持久存在的,这意味着存储在暂存空间中的数据在 sed 处理后续行时仍然可用。特殊的命令(h、H、g、G、x)用于在模式空间和暂存空间之间移动数据。这使得更复杂的操作成为可能,例如记住前一行或重新排列文本块。
  • 输入文件默认不可变性 (Input File Immutability, Default): 默认情况下,sed 读取输入文件,但不会直接修改它。转换应用于模式空间中的数据,结果被发送到标准输出。要修改原始文件,通常是将 sed 的输出重定向到一个新文件,然后替换原始文件,或者使用 GNU sed 提供的 -i 选项(原地编辑,使用时请小心,最好先备份原始文件)。
  • 标准输入 (Standard Input, stdin): 如果命令行上没有提供输入文件名,sed 会从标准输入读取。这使得 sed 可以在管道中与其他命令配合使用,处理其他命令的输出。
  • 全局应用 (Global Application): 如果没有为命令指定地址(行号或模式),sed 会将其应用于读取的每一行。

我们创建一个名为 quote.txt 的简单文本文件:

$ echo -e "There is only one thing that makes a dream impossible to achieve: the fear of failure.\n - Paulo Coelho, The Alchemist" > quote.txt

示例 1:模拟 cat (显示文件内容)

$ sed '' quote.txt

输出:

There is only one thing that makes a dream impossible to achieve: the fear of failure.
- Paulo Coelho, The Alchemist

工作流程分析:

  1. 读取 (Line 1): sed 将第一行(“There is only one thing…”)读取到模式空间。
  2. 执行 (Execute): sed 脚本是 ''(空,表示没有命令)。因此,不对模式空间执行任何操作。
  3. 显示 (Display): sed 将模式空间的内容(第一行)打印到标准输出。
  4. 读取 (Line 2): sed 将第二行(” - Paulo Coelho…”)读取到模式空间,替换了之前的内容。
  5. 执行 (Execute): 同样,不应用任何命令。
  6. 显示 (Display): sed 将模式空间的内容(第二行)打印到标准输出。
  7. 由于没有更多行,过程停止。

示例 2:从标准输入读取

$ sed ''

现在,如果你输入一行文本并按 Enter:

Hello, sed world!
Hello, sed world!

解释:第一个 “Hello, sed world!” 是你输入的行(输入)。sed 读取它,不应用任何命令(因为 ''),然后打印它(输出)。要退出此交互式 sed 会话,通常按 Ctrl+D(表示文件结束 End-Of-File)。

理解这个工作流程是预测 sed 如何转换文本以及编写更复杂、更强大脚本的关键。