带有-i选项(就地编辑)的sed命令在Ubuntu上运行良好,但在Mac上不行



我对Sed一无所知,但需要这个命令(在Ubuntu上运行良好)才能在Mac OSX上工作:

sed -i "/ $domain .*#drupalpro/d" /etc/hosts

我:

sed: 1: "/etc/hosts": extra characters at the end of h command

Ubuntu附带GNU sed,其中-i选项的后缀是可选的。OS X附带BSD sed,其中后缀是强制性的。试试sed -i ''

为了补充microtherion的有用的,切中要害的答案:

  • 与便携式解决方案
  • 附背景资料

tl;博士:

这个GNU sed (大多数Linux发行版的标准)命令的等效:

sed -i    's/foo/bar/' file
这是

BSD/macOS sed 命令:

sed -i '' 's/foo/bar/' file  # Note the '' as a *separate argument*

对于BSD/macOS sed ,以下命令do not根本不起作用:

sed -i    's/foo/bar/' file  # Breaks; script is misinterpreted as backup-file suffix
sed -i''  's/foo/bar/' file  # Ditto
sed -i -e 's/foo/bar/' file  # -e is misinterpreted as backup-file suffix

关于所有 GNU sed和BSD/macOS sed之间的差异的讨论,参见我的回答。

便携式方法:

注意:可移植在这里意味着该命令适用于所讨论的两种实现。它在POSIX意义上是不可移植的,因为-i选项不兼容POSIX。

# Works with both GNU and BSD/macOS Sed, due to a *non-empty* option-argument:
# Create a backup file *temporarily* and remove it on success.
sed -i.bak 's/foo/bar/' file && rm file.bak

的解释见下文;对于替代解决方案,包括posix兼容的解决方案,请参阅我的相关回答。


背景信息

GNU sed(大多数Linux发行版的标准)和BSD/macOS sed中, -i选项,执行就地更新[1]在其输入文件中,接受一个选项参数,该参数指定要用于备份文件的后缀(文件扩展名)

。,在两个实现中,以下命令保留原始文件file作为备份文件file.bak:

sed -i.bak 's/foo/bar/' file  # Keep original as 'file.bak'; NO SPACE between -i and .bak

即使在GNU sed中,后缀参数是可选,而在BSD/macOS sed中,后缀参数是强制性,上述语法也适用于两个实现,因为直接将选项参数(.bak)连接到选项(-i) - -i.bak,而不是-i .bak -作为可选强制性选项参数:

    -i.bak唯一的形式,适用于可选选项参数。-i.bak 也可作为强制性选项参数,作为-i .bak替代,即分别指定选项及其参数

不指定后缀——通常是这种情况——意味着不应该保留备份文件,这就是产生不兼容的地方:

  • 对于GNU sed,不指定后缀意味着直接使用-i 本身

  • 对于BSD/macOS sed,不指定后缀意味着指定空字符串作为强制后缀,而由于技术原因,空字符串只能作为单独的参数传递:即-i '' 而不是 -i''

-i''不起作用,因为对sed来说,它与-i 无法区分,因为shell有效地删除了空引号(它连接-i''并使用语法函数删除引号),并且在两个情况下仅传递-i

如果(有效地)只指定了-i,则下一个参数将被解释为选项参数:

sed -i 's/foo/bar/' file # BREAKS with BSD/macOS Sed

's/foo/bar/' -原本用于Sed 脚本(命令)-现在被解释为后缀,单词file被解释为脚本。将这样的单词解释为脚本会导致模糊的错误消息,如
sed: 1: "file": invalid command code f,
因为f被解释为Sed命令(函数)。

同样,:

sed -i -e 's/foo/bar/' file # CREATES BACKUP FILE 'file-e'

-e被解释为后缀参数,而不是Sed的-e选项(如果需要,可以用来指定多个命令)。
因此,不是保持NO备份,而是得到后缀为-e的备份文件。

这个命令没有像预期的那样工作是不太明显的,因为就地更新确实成功了,假设后缀参数的语法要求由-e参数满足。

这些备份文件的意外创建很容易被忽视,这是Crt错误答案的最有可能的解释,而这个类似问题的错误答案得到了如此多的支持(截至撰写本文时)。


[1]严格来说,一个临时文件是在后台创建的,然后替换原始文件;这种方法可能是有问题的:看看我这个答案的下半部分。

的人是你的朋友。

OS X

 -i extension
         Edit files in-place, saving backups with the specified extension.
         If a zero-length extension is given, no backup will be saved.  It
         is not recommended to give a zero-length extension when in-place
         editing files, as you risk corruption or partial content in situ-
         ations where disk space is exhausted, etc.

在OS X中,您可以使用GNU版本的sed: gsed

# if using brew
brew install gnu-sed
#if using ports
sudo port install gsed

然后,如果你的脚本应该是可移植的,根据你的操作系统,你可以定义使用哪个命令。

SED=sed
unamestr=`uname`
if [[ "$unamestr" == "Darwin" ]] ; then
    SED=gsed
    type $SED >/dev/null 2>&1 || {
        echo >&2 "$SED it's not installed. Try: brew install gnu-sed" ;
        exit 1;
    }
fi
# here your sed command, e.g.:
$SED -i "/ $domain .*#drupalpro/d" /etc/hosts

相关内容

  • 没有找到相关文章

最新更新