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


Answers:


43

在unix变体之间,shell实用程序的行为确实存在细微差别。有许多UNIX变种,具有复杂的 历史。有诸如POSIX标准及其超集Single UNIX规范之类的标准化工作。如今,大多数系统都实现了POSIX:2001(也称为Single UNIX Specification版本3),并且存在细微的差异和许多扩展。Single Unix规范不是教程,但是如果您已经知道命令的作用,则可以阅读版本3。您可以查阅它,以了解某些功能是标准功能还是特定系统的扩展。

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

关于sed,请参阅sed单个Unix规范,以获取每个系统应支持的最低标准,有关实现支持的系统手册页,以及有关大多数人使用的GNU sed手册

GNU sed中的非标准扩展之一是支持同时运行多个命令。例如,此GNU sed程序会打印包含的所有行a,但会b变为cfirst:

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; }'

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

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

请注意,在所有有关GNU扩展的情况下,用法都是非标准的。GNU sed本身是合规的,因为它做了标准允许(但不是必需的,未指定)的事情。在某些情况下,它不符合要求并且POSIXLY_CORRECT可以在环境中运行它可以提供帮助。像s/[\n]//g这样,必须删除反冲和n字符,但要删除换行符。或N命令在最后一行的行为。
斯特凡Chazelas

sed -ne '/a/ { s/b/c/g; p; }'自2016年版标准以来已成为标准。它总是便携的。见austingroupbugs.net/view.php?id=944&nbn=7
斯特凡Chazelas

60

OS X当前带有自2005年以来的FreeBSD sed。以下大多数差异也适用于其他BSD sed版本。

-EERE和GNU sed用途的OS X的sed用途-r-E-rGNU sed中的别名(在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的不会。\(\)\{,和\}是POSIX BRE。

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

i(插入),a(附加)和c(更改)必须在OS X的sed和POSIX的s中加上反斜杠和换行符,但在GNU的sed之后。GNU SED通过插入的文本后面增加一个换行符丢失iac但OS X的sed的没有。例如,sed 1ia是GNU的替代品sed $'1i\\\na\n'

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

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

OS X的sed不支持-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

4
-i -e在OSX上不起作用。它interpets -e作为后缀。
克里斯·马丁

3
@ChrisMartin是的,在OS X版本中-i,即使为空字符串,也始终需要后缀。所以-i '' -e应该工作。
waldyrious

@waldyrious它仅适用于OSX。
克里斯·马丁

是的,那是那个版本的怪癖:)
waldyrious

3
句子“ -i -e对两者都起作用”。您的回答表明存在跨平台解决方案。显然没有。
leondepeon

5

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

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

或使用perl-i来源。perl -Tpi -e 's/foo/bar/' -- "$TARGET"
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.