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

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

我在使用本网站提供的答案时遇到一些问题这个问题是关于 sed 命令用另外两行内容替换空行的问题,如果 Mac OS(对我来说是 10.6.7)上的 sed 命令不同,就会出现这个问题。我不这么认为,但想知道这个网站上的其他人是否有不同的想法。

答案1

OS X 目前附带 2005 年的 FreeBSD sed。下面的大多数差异也适用于其他 BSD sed 版本。

OS X 的 sed 用于-EERE,而 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 解释转义序列,例如\s, \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在 OS X 的 sed 和 POSIX sed 中, (insert)、a(append) 和c(change) 后面必须跟一个反斜杠和换行符,但在 GNU sed 中则不然。 GNU sed 在ia、 或插入的文本后添加缺失的换行符,c但 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

答案2

不同 UNIX 变体之间 shell 实用程序的行为确实存在细微差别。有许多UNIX变体,具有复杂的 历史。有标准化工作如那个POSIX标准及其超集单一 UNIX 规范。现在大多数系统都实现 POSIX:2001,也称为单一 UNIX 规范版本 3,有微小的偏差和许多扩展。 Single Unix 规范不是教程,但如果您已经了解命令的用途,则可以阅读第 3 版。您可以查阅它来了解某些功能是标准功能还是特定系统的扩展。

大多数 unix 用户使用 Linux 并且没有使用任何其他变体。 Linux 附带GNU实用程序,通常对标准有许多扩展。因此,您会发现很多代码可以在 Linux 上运行,但不能在其他 unice 上运行,因为它依赖于这些扩展。

关于 sed,请参阅sed 单一 Unix 规范对于每个系统应该支持的最低限度,您系统上的手册页您的实施支持什么,以及GNU sed 手册对于大多数人使用的东西。

GNU sed 中的非标准扩展之一是支持多个命令一起运行。例如,这个 GNU sed 程序打印包含 , 的所有行a,但更改bc第一个:

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/  */\
/'

答案3

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

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

答案4

另一个区别是,如果您尝试处理 LANG 或 LC_CTYPE 设置为 UTF-8 的二进制文件,Mac/BSD sed它可能会给出。不会给出错误。error: illegal byte sequenceGNU sed

如果您在 Mac/BSD 上遇到该错误,您可以尝试以下方法之一:

LC_CTYPE=C sed ...
LC_ALL=C sed ...
LANG=C sed ...

相关内容