Linux 带有 -i 选项(就地编辑)的 sed 命令在 Ubuntu 上工作正常,但在 Mac 上不工作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16745988/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 23:02:35  来源:igfitidea点击:

sed command with -i option (in-place editing) works fine on Ubuntu but not Mac

linuxmacossedbsdinplace-editing

提问by Michelle Williamson

I know nothing about Sed but need this command (which works fine on Ubuntu) to work on a Mac OSX:

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

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

I'm getting:

我越来越:

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

回答by Diego Torres Milano

man is your friend.

男人是你的朋友。

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.

回答by microtherion

Ubuntu ships with GNU sed, where the suffix for the -ioption is optional. OS X ships with BSD sed, where the suffix is mandatory. Try sed -i ''

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

回答by jcarballo

In OS X, you can use the GNU version of sed: gsed.

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

# if using brew
brew install gnu-sed

#if using ports
sudo port install gsed

Then, if your script should be portable, depending on your OS you can define which command to use.

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

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

回答by mklement0

To complement microtherion's helpful, to-the-point answer:

为了补充microtherion 有用的、直截了当的答案

  • with a portable solution
  • with background information
  • 使用便携式解决方案
  • 有背景资料

tl;dr:

tl;博士

The equivalent of this GNUsed(standard on most Linuxdistros) command:

相当于这个GNUsed(大多数Linux发行版的标准)命令:

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

is this BSD/macOSsedcommand:

这是BSD/macOSsed命令:

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

With BSD/macOSsed, the following commands do notworkat all or not as intended:

随着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

For a discussion of allthe differences between GNU sedand BSD/macOS sed, see this answerof mine.

有关GNU和 BSD/macOS之间所有差异的讨论,请参阅我的这个答案sedsed

Portable approach:

便携式方法

Note: Portablehere means that the command works with both implementations discussed. It is not portable in a POSIXsense, because the -ioption is not POSIX-compliant.

注意:此处的可移植意味着该命令适用于所讨论的两种实现。它在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

For an explanation, see below; for alternative solutions, including a POSIX-compliant one, see this related answerof mine.

有关解释,请参见下文;对于替代解决方案,包括符合 POSIX 标准的解决方案,请参阅我的这个相关答案



Background information

背景资料

In GNUsed(standard on most Linux distros) and BSD/macOSsed, the -ioption, which performs in-place updating[1]of its input files, accepts an option-argumentthat specifies what suffix(filename extension) to use for the backup fileof the file being updated.

GNUsed(在大多数Linux发行版标准)和BSD / MACOSsed-i选项,该选项进行就地更新[1]的其输入文件,接受一个选项形式参数,以指定后缀(文件扩展名),以用于该备份文件正在更新的文件

E.g., in bothimplementations, the following keeps the original file, file, as backup file file.bak:

例如,在这两种实现中,以下将原始文件file, 作为备份文件file.bak

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

Even though with GNUsedthe suffix argument is optional, whereas with BSD/macOSsedit is mandatory, the above syntax works with bothimplementations, because directly adjoining the option-argument (.bak) to the option (-i) - -i.bak, as opposed to -i .bak- works both as an optionaland a mandatoryoption-argument:

即使对于GNUsed后缀参数是optional,而对于BSD/macOSsed它是强制性的,上述语法适用于两种实现,因为直接将选项参数 ( .bak) 连接到选项 ( -i) - -i.bak,而不是-i .bak- 两者都可以作为一个可选的和一个强制性的选项参数

  • Syntax -i.bakis the onlyform that works for an optionaloption-argument.
  • Syntax -i.bakalsoworks as a mandatoryoption-argument, as an alternativeto -i .bak, i.e., specifying the option and its argument separately.
  • 语法-i.bak唯一适用于可选选项参数的形式。
  • 语法-i.bak可以作为一个强制性的选项参数,作为一个替代方案,以-i .bak,即,指定选项及其参数分别

Not specifying a suffix- which is often the case - means that no backup fileshould be kept, and that is where the incompatibility arises:

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

  • With GNUsed, not specifying a suffix means simply using -iby itself.

  • With BSD/macOSsed, not specifying a suffix means specifying the empty stringas the - mandatory - suffix, and for technicalreasons, the empty string can only be passed as a separateargument: that is, -i ''not-i''.

  • 随着GNUsed,只需使用不指定后缀手段-i本身

  • 对于BSD/macOSsed,不指定后缀意味着将空字符串指定为 - 强制 - 后缀,并且出于技术原因,空字符串只能作为单独的参数传递:即-i ''not-i''

-i''doesn't work, because to sedit is indistinguishable from just -i, because the shelleffectively removesthe empty quotes (it concatenates -iand ''and removes quotes with syntactical function), and passes just -iin bothcases.

-i''不工作,因为sed它是从仅仅区分-i,因为外壳有效地消除了空引号(它加到-i''与句法功能可以去除引号),只传递-i这两种情况下。

With (effectively) just -ispecified, it is the nextargument that is interpreted as the option-argument:

通过(有效地)刚刚-i指定,下一个参数被解释为选项参数:

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

's/foo/bar/'- intended to the the Sed script(command) - is now interpreted as the suffix, and the word fileis interpreted as the script.
Interpreting such a word as script then leads to obscure error message such as
sed: 1: "file": invalid command code f,
because the fis interpreted as a Sed command (function).

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

Similarly, with:

同样,与:

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

-eis interpreted as the suffixargument, and NOT as Sed's -eoption(which can be used to specify multiplecommands, if needed).
As as result, instead of keeping NO backup, you get a backup file with suffix -e.

-e被解释为后缀参数,而不是 Sed 的-e选项(如果需要,可用于指定多个命令)。
因此,您将获得一个后缀为-e.

That this command doesn't work as intended is less obvious, because the in-place updating does succeed, given that the syntax requirement of the suffix argument is satisfied by the -eargument.

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

That the accidental creation of these backup files easily goes unnoticed is the likeliest explanation for Crt's incorrect answerand this incorrect answer to a similar questionhaving received so many up-votes (as of this writing).

这些备份文件的意外创建很容易被忽视,这是对Crt 错误答案的最可能解释,而这个对类似问题的错误答案已经收到了如此多的赞成票(在撰写本文时)。



[1] Strictly speaking, a temporary file is created behind the scenes that then replacesthe original file; this approach can be problematic: see the bottom half of this answerof mine.

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