跳转到内容

Sed

100% developed
来自维基教科书,开放的书籍,开放的世界

sed(“stream editor”)是Unix 用于解析和转换文本文件的实用程序,它在各种操作系统上都有可用的移植版本。在许多情况下,它已被perl(或更早的AWK)取代,但在 shell 脚本中进行简单转换时,sed 仍然保留了一些用途。

Sed 是面向行的 - 它一次处理一行 - 并允许正则表达式 匹配和替换。

简单使用

[编辑 | 编辑源代码]

sed 最常用的功能是s命令(“替换”或“thes///结构”),它将一个模式替换为另一个模式;这起源于早期的 ed,并在 perl 中保留了使用。

简单来说

sed s/cat/dog/g in > out

将在文件中的“cat”替换为“dog”in并将它输出到文件out;“g”表示“全局”:替换所有匹配项,而不仅仅是给定行上的第一个匹配项。

人们通常希望使用单引号(' ')包围模式以避免 shell 错误地解释它

sed 's/cat/dog/g' in > out

一些实现要求表达式前面有-e如果有多个模式,人们无论如何都会希望使用它

sed -e 's/cat/dog/g' -e 's/meow/woof/g' in > out

Sed 也可以作为管道运行,接收标准输入并发送到标准输出。

复杂模式

[编辑 | 编辑源代码]

对于复杂的模式,人们可能希望使用-r(GNU sed)或-E(BSD sed)开关以启用“扩展正则表达式”,因为 sed 的默认转义和正则表达式可能很难使用,特别是在转义“(”时。

分组特别有用,使用 (…) 表示要匹配的组,并使用 \1, \2, …, \9 在替换模式中引用该编号组。例如,

 sed -r 's/<(.*)>/<\1><\/\1>/g'

<a> 替换为 <a></a>。这允许简单的字段解析和处理,例如重新排列多个模式组。

除了使用s命令外,人们可以在 sed 中开发复杂的程序。

面向行

[编辑 | 编辑源代码]

Sed 是面向行的 - 它一次处理一行,剥离尾随的换行符。为了对多行进行操作,人们必须使用更复杂的结构,即N命令(将下一行添加到缓冲区),或H然后是g. 参见Sed 常见问题解答,第 5.10 节

连接行

[编辑 | 编辑源代码]

对于将文件中的所有行连接起来的简单任务,最简单的方法是使用tr实用程序

tr '\n' ' '

表示“用空格替换换行符”。请注意,sed(除了 GNU sed)有空格限制,因此任何将整个文件连接成 sed 中的一行的操作都会将整个文件保存在内存中;而 tr 只从头到尾处理输入,因此没有此类内存问题。

在一个表达式中,这可以写成

tr '\n' ' ' < in > out
[编辑 | 编辑源代码]

greptr 是有用的补充 - 前者选择行,后者应用单字符转换。例如,您可以使用 grep 选择某些行,然后通过管道传递给 sed 来解析这些行。

AWK,尤其是Perl,是同类的高级语言,如果需要执行 sed 中难以完成的任务,可以使用它们作为替代方案。

POSIX 标准 sed 的命令行选项

  • -n: 仅通过 p 命令产生输出。
  • -e script
  • -f script-file

GNU sed 的命令行选项,超出了POSIX 标准 sed

  • --version
  • --help
  • --quiet--silent,除了 -n
  • --expression=script
  • --file=script-file
  • -i[SUFFIX], --in-place[=SUFFIX]
  • -l N, --line-length=N
  • --posix
  • -b, --binary
  • --follow-symlinks
  • -r, --regexp-extended
  • -s, --separate
  • -u, --unbuffered

BSD sed 的命令行选项(默认安装在 macOS 上),超出了POSIX 标准 sed

  • -E: 使用扩展正则表达式
  • -a
  • -i extension
  • -l

链接

正则表达式

[编辑 | 编辑源代码]

Sed 使用了一种特定版本的正则表达式,它与 grep 和 Perl 不同。Sed 涵盖了 POSIX 基本正则表达式(另见正则表达式/Posix 基本正则表达式)。

sed 中可用的正则表达式功能包括 *, ., ^, $, [ ], [^ ]\( \)\n\{i\}, \{i,j\} \{i,\}

GNU sed 中作为 GNU 扩展可用的正则表达式功能包括 \+\?\\b\B\w\W\s\S\`\'\<\>。此外还包括 \a(响铃字符),\f(换页),\n(换行),\r(回车),\t(水平制表符),\v(垂直制表符),\cx(Control-x),\dxxx(按十进制 ASCII 值表示的字符),\oxxx(按八进制 ASCII 值表示的字符),\xhh(按十六进制 ASCII 值表示的字符)。

sed 支持的预定义字符类包括 [:alpha:], [:blank:], [:cntrl:], [:digit:], [:graph:], [:lower:], [:print:], [:punct:], [:space:], [:upper:][:xdigit:]

sed 中不可用的正则表达式功能包括 Perl 元字符 \d\D\A\Z

链接

单行示例

[编辑 | 编辑源代码]

替换的单行示例

sed "s/concieve/conceive/" myfile.txt
  • 替换每行中第一个出现的 "concieve"。
sed "s/concieve/conceive/g" myfile.txt
  • 由于末尾有 "g",因此替换所有出现。
sed "s/concieve/conceive/g;s/recieve/receive/g" myfile.txt
  • 执行两个替换。
$ echo "abccbd" | sed "s/a\([bc]*\)d/\1/g"
bccb
  • 使用 \( 和 \) 标记组,并使用 \1 在替换部分引用该组。
  • 可能只适用于 GNU sed;需要验证。
$ echo "abccbd" | sed -r "s/a([bc]*)d/\1/g"
bccb
  • 在 GNU sed 中,它与前一个示例执行相同操作,只是使用 -r 开启扩展正则表达式,消除了在 "(" 前添加反斜杠以指示分组的需要。
  • -r 开关在 GNU sed 中可用,而在原始 Unix sed 中不可用。
$ echo "a  b" | sed -r "s/a\s*b/ab/g"
ab
  • 在 GNU sed 中,使用 "\s" 表示空格,并使用 "*" 使前一个字符组重复任意次数。需要 -r 在 GNU sed 中启用扩展正则表达式。
sed "s/\x22/'/g" myfile.txt
  • 在 GNU sed 中,将每个引号替换为单引号。\x22 指的是十六进制 ASCII 值为 22 的字符,即引号。
$ echo Hallo | sed "s/hallo/hello/gi"
hello
  • 忽略字符大小写,因为末尾有 "i"。不保留大小写,输出 "hello" 而不是 "Hello"。
$ echo a2 | sed "s/[[:alpha:]]/z/g"
z2
  • 使用 [[:alpha:]],它代表任何字母。请注意,字符类在手册中列为 "[:alpha:]",带单引号 "[".

具体示例

[编辑 | 编辑源代码]
  • 将日期格式转换为另一种格式
$ echo "03/11/2015 23:54:03" | sed -r "s/([0-9]+)\/([0-9]+)\/([0-9]+)/\3-\2-\1/g"
2015-11-03 23:54:03

Sed 不支持在 ".*?" 表达式中看到的非贪婪匹配。在 Unix shell 脚本中,您可以使用 Perl 单行命令来模拟带有非贪婪匹配的 sed

$ echo "abcbbc" | perl -pe "s/a.*?c/ac/"
acbbc
$ perl -pe "s/a.*c/ac/" # without the non-greedy "?"
ac
[编辑 | 编辑源代码]
[编辑 | 编辑源代码]
华夏公益教科书