Sed 基本命令
流编辑器 - 基本命令
Section titled “流编辑器 - 基本命令”本章介绍了几种用于文本操作的基本 SED 命令。我们将使用以下 books.txt 文件作为示例。请确保您的 books.txt 文件内容与此匹配,以获得一致的结果:
文件: `books.txt`1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3523) The Alchemist, Paulo Coelho, 1974) The Fellowship of the Ring, J. R. R. Tolkien, 4325) The Pilgrimage, Paulo Coelho, 2886) A Game of Thrones, George R. R. Martin, 864删除命令 (d)
Section titled “删除命令 (d)”d 命令从模式空间(pattern space)中删除行。被删除的行不会发送到输出流(output stream),并且原始文件保持不变,除非使用原地编辑(in-place editing)(例如,sed -i)。
语法: `[address1[,address2]]d`address1 和 address2 指定删除的起始和结束行号或模式。两者都是可选的。如果没有给出地址,则删除所有行。
示例:删除所有行(无输出)。
[jerry]$ sed 'd' books.txt此命令不产生输出,因为每行都被读入模式空间,然后在打印之前被删除。
示例:删除第 4 行。
[jerry]$ sed '4d' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3523) The Alchemist, Paulo Coelho, 1975) The Pilgrimage, Paulo Coelho, 2886) A Game of Thrones, George R. R. Martin, 864示例:删除从第 2 行到第 4 行。
[jerry]$ sed '2,4d' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12165) The Pilgrimage, Paulo Coelho, 2886) A Game of Thrones, George R. R. Martin, 864示例:删除包含模式 “Paulo Coelho” 的行。
[jerry]$ sed '/Paulo Coelho/d' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3524) The Fellowship of the Ring, J. R. R. Tolkien, 4326) A Game of Thrones, George R. R. Martin, 864示例:删除从第一个匹配 “Storm” 的行到第一个匹配 “Fellowship” 的行之间的所有行。
[jerry]$ sed '/Storm/,/Fellowship/d' books.txt输出:
5) The Pilgrimage, Paulo Coelho, 2886) A Game of Thrones, George R. R. Martin, 864您还可以使用特殊的地址字符,如 $(最后一行),或 GNU 扩展,如 M~N(从第 M 行开始每隔 N 行)。
写入命令 (w)
Section titled “写入命令 (w)”w file 命令将模式空间的内容写入指定的 file。这对于提取文件的一部分或创建备份非常有用。如果文件不存在,则创建;如果存在,则覆盖。
语法: `[address1[,address2]]w file`注意:w 和 file 之间必须有且仅有一个空格。
示例:将 books.txt 备份到 books.bak。
[jerry]$ sed -n 'w books.bak' books.txt验证复制的文件:
[jerry]$ diff books.txt books.bak[jerry]$ echo $?输出(如果文件相同):
0示例:仅将偶数行写入 junk.txt(使用 GNU SED 地址扩展 M~N)。
[jerry]$ sed -n '2~2 w junk.txt' books.txt[jerry]$ cat junk.txt输出 (cat junk.txt):
2) The Two Towers, J. R. R. Tolkien, 3524) The Fellowship of the Ring, J. R. R. Tolkien, 4326) A Game of Thrones, George R. R. Martin, 864示例:将不同作者的书存储到单独的文件中。
[jerry]$ sed -n -e '/Martin/w Martin.txt' -e '/Paulo/w Paulo.txt' -e '/Tolkien/w Tolkien.txt' books.txt检查文件内容:
[jerry]$ cat Martin.txt输出:
1) A Storm of Swords, George R. R. Martin, 12166) A Game of Thrones, George R. R. Martin, 864[jerry]$ cat Paulo.txt输出:
3) The Alchemist, Paulo Coelho, 1975) The Pilgrimage, Paulo Coelho, 288[jerry]$ cat Tolkien.txt输出:
2) The Two Towers, J. R. R. Tolkien, 3524) The Fellowship of the Ring, J. R. R. Tolkien, 432追加命令 (a)
Section titled “追加命令 (a)”a 命令在指定的行或匹配模式的行 之后 追加文本。要追加的文本跟在命令后面,如果跨越多行,则用反斜杠分隔。
语法:`[address]a\text to append`(对于多行文本,除了最后一行,后续每一行文本也必须以 `\` 结尾。) 或者对于单行文本:`[address]a text to append` (GNU sed 允许文本在同一行,POSIX 要求 `a` 后必须换行,除非它是脚本中的最后一个命令。) 可移植性的最佳实践是 `[address]a\`,然后在下一行写文本。示例:在第 4 行之后追加一个新的书籍条目。
[jerry]$ sed '4a\7) Adultery, Paulo Coelho, 234' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3523) The Alchemist, Paulo Coelho, 1974) The Fellowship of the Ring, J. R. R. Tolkien, 4327) Adultery, Paulo Coelho, 2345) The Pilgrimage, Paulo Coelho, 2886) A Game of Thrones, George R. R. Martin, 864示例:使用 $ 地址在文件末尾追加文本。
[jerry]$ sed '$a\7) Adultery, Paulo Coelho, 234' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3523) The Alchemist, Paulo Coelho, 1974) The Fellowship of the Ring, J. R. R. Tolkien, 4325) The Pilgrimage, Paulo Coelho, 2886) A Game of Thrones, George R. R. Martin, 8647) Adultery, Paulo Coelho, 234更改命令 (c)
Section titled “更改命令 (c)”c 命令用新文本替换整个现有行。如果指定了行范围,则所有这些行作为一个组被新文本(可以是单行或多行)替换。
语法:`[address1[,address2]]c\replacement text`(对于 `replacement text`,换行符/反斜杠规则与 `a` 和 `i` 命令类似。)示例:替换第三行。
[jerry]$ sed '3c\3) Adultery, Paulo Coelho, 324' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3523) Adultery, Paulo Coelho, 3244) The Fellowship of the Ring, J. R. R. Tolkien, 4325) The Pilgrimage, Paulo Coelho, 2886) A Game of Thrones, George R. R. Martin, 864插入命令 (i)
Section titled “插入命令 (i)”i 命令类似于 a,但它在指定的行或模式匹配的行 之前 插入文本。
语法:`[address]i\text to insert`(对于 `text to insert`,换行符/反斜杠规则与 `a` 命令类似。)示例:在第四行之前插入一个新条目。
[jerry]$ sed '4i\7) Adultery, Paulo Coelho, 324' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3523) The Alchemist, Paulo Coelho, 1977) Adultery, Paulo Coelho, 3244) The Fellowship of the Ring, J. R. R. Tolkien, 4325) The Pilgrimage, Paulo Coelho, 2886) A Game of Thrones, George R. R. Martin, 864示例:在最后一行($)之前插入两行。
[jerry]$ sed '$i\7) Adultery, Paulo Coelho, 324\8) Eleven Minutes, Paulo Coelho, 304' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3523) The Alchemist, Paulo Coelho, 1974) The Fellowship of the Ring, J. R. R. Tolkien, 4325) The Pilgrimage, Paulo Coelho, 2887) Adultery, Paulo Coelho, 3248) Eleven Minutes, Paulo Coelho, 3046) A Game of Thrones, George R. R. Martin, 864转换命令 (y)
Section titled “转换命令 (y)”y 命令进行字符转写(transliterate)。它根据位置将 source-list 中的字符替换为 destination-list 中对应的字符。
语法: `[address1[,address2]]y/source-list/destination-list/`重要提示:source-list 和 destination-list 必须具有相同的字符数。这些列表中不支持正则表达式(Regular expressions)或字符类(character classes)。
示例:将特定的阿拉伯数字(0, 1, 2, 5)转换为简单的类似罗马数字的字符(分别对应 X, I, X, V)。
[jerry]$ echo "1 5 15 20" | sed 'y/0125/XIXV/'输出:
I V IV XX解释:‘1’ 变为 ‘I’,‘5’ 变为 ‘V’。所以 ‘15’ 变为 ‘IV’。‘2’ 变为 ‘X’,‘0’ 变为 ‘X’。所以 ‘20’ 变为 ‘XX’。
列表命令 (l)
Section titled “列表命令 (l)”l 命令以一种明确的方式显示模式空间的内容,展示非打印字符(non-printable characters),如制表符(\t)和行尾符($)。可选的 len 参数(GNU 扩展)指定行换行的长度。
语法:`[address1[,address2]]l``[address1[,address2]]l [len]` (GNU 扩展)示例:创建一个文件 tabbed_books.txt,其中用制表符代替一些空格以作演示。
[jerry]$ sed 's/ /\t/2g' books.txt > tabbed_books.txt现在显示 tabbed_books.txt 中的隐藏字符:
[jerry]$ sed -n 'l' tabbed_books.txt输出(会因制表符插入位置而异,示例显示 \t 表示制表符,$ 表示行尾):
1) A Storm of\tSwords,\tGeorge R. R. Martin, 1216$2) The Two\tTowers,\tJ. R. R. Tolkien, 352$3) The Alchemist,\tPaulo\tCoelho, 197$4) The Fellowship\tof\tthe Ring, J. R. R. Tolkien, 432$5) The Pilgrimage,\tPaulo\tCoelho, 288$6) A Game of\tThrones,\tGeorge R. R. Martin, 864$示例:将 books.txt 中的行在 25 个字符后换行(GNU 扩展)。
[jerry]$ sed -n 'l 25' books.txt输出:
1) A Storm of Swords,Geo\rge R. R. Martin,1216$2) The Two Towers,J. R. \R. Tolkien,352$3) The Alchemist,Paulo C\oelho,197$4) The Fellowship of the\ Ring,J. R. R. Tolkien,\432$5) The Pilgrimage,Paulo \Coelho,288$6) A Game of Thrones,Geo\rge R. R. Martin,864$换行限制为 0(GNU 扩展)表示除非存在实际的换行符,否则永远不换行。
退出命令 (q)
Section titled “退出命令 (q)”q 命令导致 SED 停止处理并立即退出。它可以接受一个可选的 value(GNU 扩展)作为退出状态(exit status)。
语法:`[address]q``[address]q [value]` (GNU 扩展)注意:q 只接受一个地址,而不是一个范围。
示例:打印文件的前 3 行,然后退出。
[jerry]$ sed '3q' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3523) The Alchemist, Paulo Coelho, 197示例:找到 “The Alchemist” 时退出,退出状态为 100(GNU 扩展)。
[jerry]$ sed '/The Alchemist/q 100' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3523) The Alchemist, Paulo Coelho, 197验证退出状态:
[jerry]$ echo $?输出:
100读取命令 (r)
Section titled “读取命令 (r)”r file 命令读取 file 的内容,并在当前行(或匹配地址的行)之后将它们追加到输出中。
语法: `[address]r file`注意:r 和 file 之间必须有且仅有一个空格。
示例:创建 junk.txt 并将其内容插入到 books.txt 的第 3 行之后。
[jerry]$ echo "This is junk text." > junk.txt[jerry]$ sed '3r junk.txt' books.txt输出:
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 3523) The Alchemist, Paulo Coelho, 197This is junk text.4) The Fellowship of the Ring, J. R. R. Tolkien, 4325) The Pilgrimage, Paulo Coelho, 2886) A Game of Thrones, George R. R. Martin, 864GNU SED 也接受 r 命令的地址范围,将文件内容插入到每个匹配行之后。
执行命令 (e) (GNU 扩展)
Section titled “执行命令 (e) (GNU 扩展)”e [command] 命令(GNU 扩展)执行外部 command。如果省略 command,则执行模式空间的内容作为命令。
语法: `[address1[,address2]]e [command]`示例:在处理第 3 行之前执行 date 命令。
[jerry]$ sed '3e date' books.txt输出(日期/时间将是当前的):
1) A Storm of Swords, George R. R. Martin, 12162) The Two Towers, J. R. R. Tolkien, 352[当前日期和时间会显示在这里,例如,Tue Jul 23 10:30:00 UTC 2024]3) The Alchemist, Paulo Coelho, 1974) The Fellowship of the Ring, J. R. R. Tolkien, 4325) The Pilgrimage, Paulo Coelho, 2886) A Game of Thrones, George R. R. Martin, 864示例:如果 e 没有给出命令,SED 会执行模式空间的内容。创建 commands.txt:
[jerry]$ printf "date\ncal\nuname\n" > commands.txt[jerry]$ cat commands.txt输出 (cat commands.txt):
datecaluname现在通过 SED 执行这些命令:
[jerry]$ sed 'e' commands.txt输出(将显示当前日期、日历和系统名称,如 ‘Linux’):
[Output of 'date' command][Output of 'cal' command (current month's calendar)][Output of 'uname' command, e.g., Linux]多行命令 (N, P, D)
Section titled “多行命令 (N, P, D)”SED 主要逐行操作,但有些命令可以在模式空间中处理多行。
下一行命令 (N)
Section titled “下一行命令 (N)”N 命令将 下一 输入行附加到模式空间,并用嵌入的换行符(\n)分隔。这允许跨越行边界的操作。
语法: `[address1[,address2]]N`示例:将 books_split.txt 中的成对行(书名在一行,作者在下一行)合并到单行中。为此,我们假设 books_split.txt 内容如下:
文件: `books_split.txt`A Storm of SwordsGeorge R. R. MartinThe Two TowersJ. R. R. Tolkien...[jerry]$ sed 'N; s/\n/, /' books_split.txt输出(前几行):
A Storm of Swords, George R. R. MartinThe Two Towers, J. R. R. TolkienThe Alchemist, Paulo Coelho...工作原理:N 读取第 1 行(书名),然后附加第 2 行(作者),因此模式空间变为 “书名\n作者”。s/\n/, / 将 \n 替换为 ”, “。这个过程对后续成对的行重复执行。
打印多行命令 (P)
Section titled “打印多行命令 (P)”P 命令打印多行模式空间中直到第一个嵌入换行符(\n)的部分。常与 N 命令一起使用。
语法: `[address1[,address2]]P`示例:使用 books_split.txt,仅打印书名(每对行的第一行)。
[jerry]$ sed -n 'N;P' books_split.txt输出(前几行):
A Storm of SwordsThe Two TowersThe Alchemist...如果没有 N 或其他多行操作,P 的行为就像 p 一样(打印整个模式空间)。
删除多行命令 (D)
Section titled “删除多行命令 (D)”D 命令删除多行模式空间中直到第一个嵌入换行符的部分。如果模式空间变为空,SED 将开始一个新的循环。否则,它将使用剩余的内容重新启动脚本,而不再读取新行。这对于创建处理多行缓冲区部分的循环非常强大。
语法: `[address1[,address2]]D`版本检查命令 (v) (GNU 扩展)
Section titled “版本检查命令 (v) (GNU 扩展)”v [version] 命令(GNU 扩展)检查 SED 版本是否至少为 [version]。如果不是,则中止。这在脚本中很少使用;sed --version 更常用于手动检查。
语法: `[address1[,address2]]v version`示例:检查当前的 SED 版本。
[jerry]$ sed --version输出(示例):
sed (GNU sed) 4.8...示例:如果版本低于 4.9 则中止(假设当前版本为 4.8)。
[jerry]$ sed 'v 4.9' books.txt输出(如果版本低于 4.9):
sed: -e expression #1, char 5: expected newer version of sed如果版本检查通过(例如,sed 'v 4.8' books.txt),命令将正常进行,打印 books.txt 中的行。