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

Mic*_*son 95 linux macos bsd sed inplace-editing

我对Sed一无所知但是需要这个命令(在Ubuntu上运行正常)才能在Mac OSX上运行:

sed -i "/ $domain .*#drupalpro/d" /etc/hosts
Run Code Online (Sandbox Code Playgroud)

我越来越:

sed: 1: "/etc/hosts": extra characters at the end of h command
Run Code Online (Sandbox Code Playgroud)

mic*_*ion 148

Ubuntu附带GNU sed,其中该-i选项的后缀是可选的.OS X附带BSD sed,后缀是必需的.尝试sed -i ''

  • @ pal4life关键是你需要*******************"'$ HOME/.bashrc` (7认同)
  • 如果你需要在macOS(OS X,BSD)和Linux等上使用相同的脚本,那么你必须使用备份后缀(例如`.bak`),你必须将它附加到`-i`选项 - sed -i.bak ......` 如果不这样做,脚本将无法在两个平台之一上正常运行.GNU`sed`不喜欢BSD`sed'需要编辑的空参数; 你不能将空参数附加到`-i`,因为它是空的并且与`-i`无法区分.另外,由于设计相互矛盾,`-i`选项不会被POSIX标准化为`-i`; 它无法调和不可和解的. (4认同)
  • 哦,如果你不想备份,运行`sed`后运行`rm -f/etc/hosts.bak`.这比试图找出你所安装的`sed`变种或我见过的其他小玩意更简单.我希望您将文件保留在版本控制之下(或以其他方式备份),以便在您的`sed`脚本中存在错误时可以恢复.当然,`.bak`文件为您提供了保护. (3认同)
  • 所以只需用单引号跟随sed -i,sed -i'1i export PATH ="$ HOME/.composer/vendor/bin:$ PATH"'$ HOME/.bashrc仍然不适用于我 (2认同)

mkl*_*nt0 79

补充microtherion的有用,重点答案:

  • 使用便携式解决方案
  • 与背景信息

tl;博士:

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

sed -i    's/foo/bar/' file
Run Code Online (Sandbox Code Playgroud)

这是BSD/macOS sed命令:

sed -i '' 's/foo/bar/' file  # Note the '' as a *separate argument*
Run Code Online (Sandbox Code Playgroud)

随着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
Run Code Online (Sandbox Code Playgroud)

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

便携式方法:

注意:此处的Portable表示该命令适用于所讨论的两种实现.它在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
Run Code Online (Sandbox Code Playgroud)

有关解释,请参阅下文; 对于替代解决方案,包括符合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
Run Code Online (Sandbox Code Playgroud)

即使GNU sed后缀参数是可选的,而用BSD/MACOS sed它是强制性的,上面的语法可与这两种实施方式中,因为该选项形式参数(直接邻接.bak)的选项(-i) - -i.bak,而不是-i .bak-既充当一个可选的强制性的选项参数:

  • 语法-i.bak唯一适用于可选 option-argument的形式.
  • 语法-i.bak 可以作为一个强制性的选项参数,作为一个替代方案,以-i .bak,即,指定选项及其参数分别.

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

  • 随着GNU sed,不指定后缀是指仅使用-i 本身.

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

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

使用(有效)-i指定,它是下一个被解释为option-argument的参数:

sed -i 's/foo/bar/' file # BREAKS with BSD/macOS Sed
Run Code Online (Sandbox Code Playgroud)

'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'
Run Code Online (Sandbox Code Playgroud)

-e被解释为后缀参数,而不是Sed的-e选项(如果需要,可以用于指定多个命令).
因此,您将获得带有后缀的备份文件,而不是保留NO备份-e.

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

这些备份文件的意外创建很容易被忽视,这是对Crt不正确答案的最有可能的解释,以及收到如此多的向上投票的类似问题的错误答案(截至本文撰写时).


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

  • 这是对这个问题的正确和最丰富的答案.不知道是谁投了它,但没有理由表达downvote,而我有很多理由接受这个而不是其他答案. (6认同)
  • @CássioRenan:原则上,是的,但是`sed's/foo/bar'file> file.bak && mv file.bak file`(如[one linked answer]所示(https://stackoverflow.com/a/) 44877280/45375))更简单.如果`-i`可用并且可移植性不是问题,那么它的使用是可取的,因为它会保留原始文件的属性,尽管它仍然会破坏符号链接 - 请参阅[另一个链接的答案]的下半部分( /sf/answers/2104649991/).符合POSIX的方法不仅具有符号链接问题,而且只是创建一个具有默认权限的新文件,... (2认同)

Die*_*ano 21

男人是你的朋友.

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.
Run Code Online (Sandbox Code Playgroud)


jca*_*llo 6

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

# if using brew
brew install gnu-sed

#if using ports
sudo port install gsed
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

  • 这是救了我的人。我升级了我的安装并将 /usr/local/opt/gnu-sed/libexec/gnubin 添加到我的路径中。我在 OSX 10.12.6 上。 (2认同)