我在使用本网站提供的答案时遇到一些问题这个问题是关于 sed 命令用另外两行内容替换空行的问题,如果 Mac OS(对我来说是 10.6.7)上的 sed 命令不同,就会出现这个问题。我不这么认为,但想知道这个网站上的其他人是否有不同的想法。
答案1
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 解释转义序列,例如\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 在i
、a
、 或插入的文本后添加缺失的换行符,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
,但更改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/ */\
/'
答案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 sequence
GNU sed
如果您在 Mac/BSD 上遇到该错误,您可以尝试以下方法之一:
LC_CTYPE=C sed ...
LC_ALL=C sed ...
LANG=C sed ...