sed 文本流编辑器
sed(Stream EDitor,流编辑器)是一个用于文本转换的强大命令行工具。它在文本流上运行,根据正则表达式和特定命令执行替换、删除、插入和其他操作。与许多文本编辑器不同,sed 不需要打开文件进行交互式会话。它逐行处理输入流,按要求进行修改,然后输出结果。这使其成为自动化重复性编辑任务的理想选择,尤其是在 Shell 脚本中。了解 sed 对于高效的日志文件分析、数据处理和系统管理自动化非常重要。
1. sed 的基本语法与操作
sed 的基本语法如下:
sed '命令' 输入文件其中,命令 (command) 指定要执行的操作,输入文件 (inputfile) 是要处理的文件。如果没有指定输入文件,sed 将从标准输入读取。默认情况下,输出会被发送到标准输出,这意味着它会打印在终端屏幕上。
1.1 替换 (s) 命令
替换命令 s (Substitution) 是最常用的 sed 命令。它用替换字符串替换匹配到的模式。一般格式为:
sed 's/模式/替换内容/' 输入文件解析:
s: 替换命令。模式 (pattern): 要搜索的正则表达式。替换内容 (replacement): 用于替换匹配模式的字符串。/: 分隔符,可以是任何字符,但通常使用正斜杠。
示例 1:基本替换
假设你有一个名为 myfile.txt 的文件,内容如下:
This is a test file.
This file is for testing purposes.要将 "test" 替换为 "sample",你可以使用以下命令:
sed 's/test/sample/' myfile.txt输出:
This is a sample file.
This file is for sampling purposes.注意:每行只有第一个出现的 "test" 被替换了。
示例 2:全局替换
要替换每行中所有出现的 "test",请使用 g (global) 标志:
sed 's/test/sample/g' myfile.txt示例 3:使用不同的分隔符
如果你的模式或替换字符串中包含正斜杠,你可以使用不同的分隔符来避免转义它们。例如,使用 # 作为分隔符:
sed 's#this/that#that/this#g' myfile.txt如果 myfile.txt 包含带有 "this/that" 的行,它们将被替换为 "that/this"。
1.2 删除 (d) 命令
d (Deletion) 命令删除匹配特定模式或在指定范围内的行。
示例 1:删除包含某模式的行
要从 myfile.txt 中删除所有包含单词 "testing" 的行:
sed '/testing/d' myfile.txt示例 2:删除指定行号
要删除 myfile.txt 的第二行:
sed '2d' myfile.txt示例 3:删除连续多行
要删除第 2 到第 4 行:
sed '2,4d' myfile.txt1.3 插入 (i) 与追加 (a) 命令
i (Insertion) 命令在匹配模式或行号的行之前插入文本。a (Append) 命令在匹配模式或行号的行之后追加文本。
示例 1:在某行前插入文本
要在 myfile.txt 中包含单词 "testing" 的任何行之前插入一行 "New line before testing":
sed '/testing/i New line before testing' myfile.txt示例 2:在某行后追加文本
要在 myfile.txt 中包含单词 "testing" 的任何行之后追加一行 "New line after testing":
sed '/testing/a New line after testing' myfile.txt示例 3:在指定行号前后插入/追加
要在第 2 行前插入 "New line before line 2",并在第 2 行后追加 "New line after line 2":
sed '2i New line before line 2' myfile.txt | sed '2a New line after line 2'1.4 更改 (c) 命令
c (Change) 命令用新文本替换整行内容。
示例 1:更改包含某模式的行
要将包含 "test" 的任何行替换为 "This line has been changed":
sed '/test/c This line has been changed' myfile.txt示例 2:更改指定行号
要将第三行替换为 "This is the new third line":
sed '3c This is the new third line' myfile.txt1.5 读取 (r) 与 写入 (w) 命令
r(Read) 命令读取另一个文件的内容,并将其追加到匹配模式或行号的行之后。 示例: 要在myfile.txt中包含 "test" 的任何行之后追加otherfile.txt的内容:
sed '/test/r otherfile.txt' myfile.txtw(Write) 命令将匹配模式的行写入一个新文件。
示例: 要将myfile.txt中所有包含 "test" 的行写入名为test_lines.txt的新文件中:
sed '/test/w test_lines.txt' myfile.txt2. sed 中的正则表达式
sed 严重依赖正则表达式进行模式匹配。扎实理解正则表达式是有效使用 sed 的关键。(这建立在上一章对正则表达式的介绍之上)。
2.1 基础正则表达式元字符
| 元字符 | 描述 | 示例 |
|---|---|---|
. | 匹配除换行符以外的任意单个字符。 | a.c 匹配 "abc", "adc", "aec" 等。 |
* | 匹配前面的字符零次或多次。 | ab*c 匹配 "ac", "abc", "abbc" 等。 |
+ | (ERE特有) 匹配前面的字符一次或多次。 | ab+c 匹配 "abc", "abbc",但不匹配 "ac"。 |
? | (ERE特有) 匹配前面的字符零次或一次。 | ab?c 匹配 "ac", "abc"。 |
[] | 匹配方括号内的任意单个字符。也支持范围如 [a-z]。 | [aeiou] 匹配任何元音字母。 |
[^] | 匹配不在方括号内的任意单个字符。 | [^0-9] 匹配任何非数字字符。 |
^ | 匹配一行的开头。 | ^abc 匹配以 "abc" 开头的行。 |
$ | 匹配一行的结尾。 | abc$ 匹配以 "abc" 结尾的行。 |
\ | 转义特殊字符,使其按字面意义匹配。 | a\.b 匹配 "a.b"。 |
() | (ERE特有) 分组正则表达式的部分。可以被反向引用。 | (ab)+ 匹配一次或多次 "ab"。 |
| | 作为 "OR"(或)运算符。 | abc|def 匹配 "abc" 或 "def"。(在 BRE 中需转义,ERE 中不需要)。 |
示例 1:匹配特定模式
要查找 myfile.txt 中以数字开头的行:
sed -n '/^[0-9]/p' myfile.txt-n 选项抑制默认输出,而 p 命令只打印匹配的行。^ 匹配行首,[0-9] 匹配任意数字。
2.2 扩展正则表达式 (ERE)
默认情况下,sed 使用基础正则表达式 (BRE)。要使用功能更丰富、语法更易读的扩展正则表达式 (ERE),请使用 -E 选项(在某些系统上是 -r)。ERE 允许你直接使用 +、?、| 和括号 () 等元字符,而无需对它们进行转义。
示例:使用 | (OR) 与 ERE
要将 "abc" 或 "def" 替换为 "xyz":
sed -E 's/abc|def/xyz/g' myfile.txt如果没有 -E,你需要转义 |:
sed 's/abc\|def/xyz/g' myfile.txt2.3 反向引用 (Backreferences)
反向引用允许你在替换字符串中引用先前匹配的分组。它们由 \1, \2, \3 等表示,其中 \1 指代第一个捕获的分组,\2 指代第二个,依此类推。
示例:交换两个单词的位置
假设你有像 "word1 word2" 这样的行,你想交换这两个单词的顺序。
sed -E 's/([a-zA-Z]+) ([a-zA-Z]+)/\2 \1/g' myfile.txt解析:
([a-zA-Z]+): 匹配一个或多个字母并将其捕获为组 1。: 匹配中间的空格。([a-zA-Z]+): 匹配一个或多个字母并将其捕获为组 2。\2 \1: 将匹配到的文本替换为组 2、一个空格、然后是组 1。
3. sed 高级技巧
3.1 寻址 (Addresses) 机制
地址指定 sed 命令应该对哪些行执行操作。我们已经看到了使用行号和正则表达式模式作为地址的例子。地址可以被组合并以更复杂的方式使用。
示例:使用行号范围和模式
仅对第 5 到第 10 行应用替换命令:
sed '5,10s/old/new/g' myfile.txt对从匹配 "start_pattern" 的行开始,到匹配 "end_pattern" 的行结束的区块应用替换:
sed '/start_pattern/,/end_pattern/s/old/new/g' myfile.txt3.2 执行多个命令
你可以使用几种方法执行多个 sed 命令:
- 使用
-e选项:
sed -e 's/pattern1/replacement1/g' -e 's/pattern2/replacement2/g' myfile.txt- 使用分号
;:
sed 's/pattern1/replacement1/g; s/pattern2/replacement2/g' myfile.txt- 使用脚本文件:
创建一个文件(例如my_sed_script.sed),内容如下:
s/pattern1/replacement1/g
s/pattern2/replacement2/g然后运行:
sed -f my_sed_script.sed myfile.txt脚本文件方法对于复杂的 sed 命令序列非常有用。
3.3 保持空间 (The Hold Space)
保持空间是一个临时缓冲区,你可以在其中存储行以供以后使用。sed 提供了操作保持空间的命令:
h: 将模式空间(当前行)的内容复制到保持空间(覆盖)。H: 将模式空间的内容追加到保持空间。g: 将保持空间的内容复制到模式空间。G: 将保持空间的内容追加到模式空间。x: 交换模式空间和保持空间的内容。
这些命令非常强大,但一开始可能会让人感到困惑。
示例:复制一行
要复制文件中的每一行:
sed 'H;G' myfile.txt解析:
H: 将当前行(模式空间)追加到保持空间。G: 将保持空间(现在包含原始行)追加到模式空间。模式空间现在包含原始行以及紧跟其后的原始行(完成复制)。