it-swarm.cn

Mac OSX上的sed与其他“标准” sed之间的区别?

我在使用本网站上提供的答案时遇到一些问题 关于sed命令用其他两行内容替换空白行的问题 ,如果在Mac上使用sed命令,则会出现此问题操作系统(对我来说是10.6.7)是不同的。我认为并非如此,但我想知道该网站上的其他人是否有不同的看法。

67
Peter Grill

在Unix变体之间,Shell实用程序的行为确实存在细微差别。有很多 unix 变体,带有 complex历史标准化工作 ,例如 [〜#〜] posix [〜#〜] 标准及其超集 单一UNIX规范 。如今,大多数系统都实现POSIX:2001,也称为 单一UNIX规范版本3 ,但存在细微的差异和许多扩展。 Single Unix规范不是教程,但是如果您已经知道命令的作用,则可以阅读版本3。您可以查阅它,以了解某些功能是标准功能还是特定系统的扩展。

大部分的Unix用户使用Linux,并且未使用任何其他变体。 Linux附带 [〜#〜] gnu [〜#〜] 实用程序,该实用程序通常对该标准进行了许多扩展。因此,您会发现很多代码可以在Linux上运行,但不能在其他unices上运行,因为它依赖于这些扩展。

关于sed,请参考 sed单个Unix规范 ,以获取每个系统应支持的最低标准, 手册页在您的系统上 了解实现支持的内容,以及 GNU sed手册 了解大多数人所使用的内容。

Sed中的GNU sed)中的一个非标准扩展支持多个命令一起运行。例如,此GNU sed程序将打印包含a的所有行。 ,但先将b更改为c

sed -ne '/a/ {s/b/c/g; p}'

{}实际上是单独的命令,因此,为了实现完全的可移植性,您需要在单独的行中(在文件中)或在单独的-e参数中(在命令行上)指定它们。 {之后缺少命令分隔符,并且使用;作为命令分隔符是常见的扩展。 }之前缺少命令分隔符是一种较不常见的扩展。这是符合标准的:

sed -n -e '/a/ {' -e 's/b/c/g' -e p -e '}'

这是非标准的,但通常被接受:

sed -ne '/a/ { s/b/c/g; p; }'

另一个非标准但常见的扩展名是使用\n来表示s替换文本中的换行符(在正则表达式中的使用是标准的)。可移植的方法是在sed脚本中包含反斜杠换行符。另一个常见的扩展名是正则表达式中的\+\?\|表示一个或多个,最多一个,并且可以交替使用; 便携式基本正则表达式 没有这些。例如,第一个命令是用换行符替换空格连续序列的一种非便携式方法;第二个命令是符合标准的等效命令。

sed -e 's/ \+/\n/'
sed -e 's/  */\
/'
47

OS X当前从2005年开始附带FreeBSD sed。以下大多数差异也适用于其他BSD sed版本。

OS X的sed使用-E表示ERE,而GNU sed则使用-r-E是GNU sed中-r的别名(在4.2中添加,直到4.3才记录)。较新版本的FreeBSD和NetBSD sed支持-E-r。 OpenBSD sed仅支持-E

-i ''可与OS X的sed一起使用,但不能与GNU sed一起使用。 -i可与GNU sed,NetBSD的最新版本,OpenBSD sed一起使用,但不能与OS X的sed一起使用。 -i -e可以同时使用,但是在FreeBSD的情况下,sed备份原始文件,并在文件名后附加-e(并且您最多可以将一个表达式传递给sed)。

GNU sed解释转义序列,例如\t\n\001\x01\w\b。 OS X的sed和POSIX的sed只解释\n(但不能解释s的替换部分)。

GNU sed在BRE中解释\|\+\?,但OS X的sed和POSIX的sed不解释。 \(\)\{\}是POSIX BRE。

GNU sed允许省略;}之前的换行符,但OS X的sed不允许。

i(插入),a(追加)和c(更改)必须在OS X的sed和POSIX sed中加上反斜杠和换行符,而在GNU sed中则不需要。 GNU sed在iac插入的文本之后添加了缺少的换行符,但OS X的sed没有。例如,sed 1iased $'1i\\\na\n'的GNU替代。

例如,printf a|sed -n p在OS X的sed中添加换行符,而不在GNU的sed中添加换行符。

OS X的sed不支持I(不区分大小写)或M(多行)修饰符。 FreeBSD sed的较新版本支持I

OS X的s不支持-s--separate),-u--unbuffered)或-z--null-data)。

GNU sed不支持的一个BSD选项是-a,这使w附加到文件而不是截断文件。

无法与OS X的sed一起使用的GNU sed命令的示例:

sed /pattern/,+2d # like `sed '/pattern/{N;N;d;}'`
sed -n 0~3p # like `awk NR%3==0`
sed /pattern/Q # like `awk '/pattern/{exit}1'` or `sed -n '/pattern/,$!p'`
sed 's/\b./\u&/g' # \u converts the next character to uppercase
sed 's/^./\l&/' # \l converts the next character to lowercase
sed -i '1ecat file_to_prepend' file # e executes a Shell command
sed -n l0 # 0 disables wrapping
69
Lri

我发现在Linux和Mac上具有相同脚本的最佳方法是:

sed -i.bak -e 's/foo/bar/' -- "${TARGET}" &&
  rm -- "${TARGET}.bak"
6
vikrantt