Sed
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
grep 和 tr 是有用的补充 - 前者选择行,后者应用单字符转换。例如,您可以使用 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
链接
- 2 调用 在 sed 手册中,gnu.org
- Unix sed(1) 手册页 在 man.cat-v.org 上
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 手册中,gnu.org
- 3.9 GNU 扩展用于正则表达式中的转义,在 sed 手册中,gnu.org
替换的单行示例
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
- GNU sed 用户手册(单页) at gnu.org
- sed(1) OS X 手册页 at developer.apple.com
- Unix sed(1) 手册页 在 man.cat-v.org 上
- Sed 常见问题解答 at sed.sourceforge.net
- Sed 实例,第一部分 at ibm.com
- 维基百科:sed