sed命令与-i选项(就地编辑)在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的帮助,点对点的答案 :

  • 采用便携式解决scheme
  • 与背景信息

tl; dr

相当于这个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 ,以下命令根本不起作用

 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 

有关说明,请参阅下文; 对于其他解决scheme,包括符合POSIX标准的解决scheme,请参阅我的相关答案 。


背景信息

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

例如,在这两个实现中,以下内容将原始文件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是适用于可选选项参数的唯一forms。
  • 语法-i.bak 作为强制选项参数使用,作为-i .bak替代方法 ,即分别指定选项及其参数。

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

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

  • 使用BSD / macOS sed ,不指定后缀意味着将空string指定为 – mandatory – suffix, 由于技术原因,空string只能作为单独的parameter passing :即-i '' -i''

-i''不起作用,因为sed-i不能区分 ,因为shell有效地删除了空引号(它将-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参数满足后缀参数的语法要求。

这些备份文件的意外创build很容易被忽视,这是对Crt错误答案的最可能的解释,也是对类似问题获得如此多的赞成票的错误答案 (截至撰写本文)。


[1]严格来说,在后台创build临时文件,然后replace原始文件; 这种方法可能会有问题:请参阅我的答案的下半部分。

男人是你的朋友。

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中,您可以使用sed: gsed的GNU版本。

 # 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, eg: $SED -i "/ $domain .*#drupalpro/d" /etc/hosts