在Mac(BSD)和Linux上均可使用的sed in-place标志

是否有没有备份的sed todo in-place编辑的调用,可以在Linux和Mac上使用? 尽pipeOS X附带的BSD sed似乎需要sed -i '' … ,但是GNU sed Linux发行版通常将解释为空input文件名(而不是备份扩展名),并且需要sed -i …

是否有任何命令行语法,这两种口味的作品,所以我可以在两个系统上使用相同的脚本?

如果你真的想用sed -i '的方式,下面的工作在GNU和BSD / Mac sed

 sed -i.bak 's/foo/bar/' filename 

注意缺less空间和点。

certificate:

 # GNU sed % sed --version | head -1 GNU sed version 4.2.1 % echo 'foo' > file % sed -i.bak 's/foo/bar/' ./file % ls file file.bak % cat ./file bar # BSD sed % sed --version 2>&1 | head -1 sed: illegal option -- - % echo 'foo' > file % sed -i.bak 's/foo/bar/' ./file % ls file file.bak % cat ./file bar 

很明显,你可以删除.bak文件。

这适用于GNU sed,但不适用于OS X:

 sed -i -e 's/foo/bar/' target.file sed -i'' -e 's/foo/bar/' target.file 

这适用于OS X,但不适用于GNU sed:

 sed -i '' -e 's/foo/bar/' target.file 

在OS X上

  • 因为备份文件的扩展-e被设置为-e所以不能使用sed -i -e -e
  • 不能使用sed -i'' -e出于相同的原因,它需要在-i''之间的空格。

在OSX上时,我总是通过Homebrew安装GNU sed版本,以避免在脚本中出现问题,因为大多数脚本都是为GNU sed版本编写的。

 brew install gnu-sed --with-default-names 

然后你的BSD sed将被GNU sedreplace。

或者,您可以安装没有默认名称,但是:

  • 安装gnu-sed后按照说明更改PATH
  • 检查你的脚本,根据你的系统selectgsed还是sed

没有办法让它工作。

一种方法是使用临时文件,如:

 TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX` sed -e "s/abc/def/" some/file > $TMP_FILE mv $TMP_FILE some/file 

这对两者都有效

答:不可以

最初接受的答案实际上并没有做到要求(正如评论中指出的那样)。 (当我查找file-e在我的目录中随机出现的原因时,我find了这个答案。)

显然没有办法使sed -i在MacOS和Linuces上始终如一地工作。

我的build议是,不要用sed (具有复杂的故障模式)进行就地更新,而是生成新的文件并在之后对其进行重命名。 换句话说:避免-i

正如Noufal Ibrahim所问,为什么你不能使用Perl? 任何Mac都将具有Perl,并且很less有Linux或BSD发行版在基本系统中不包含某些版本的Perl。 可能实际上缺lessPerl的唯一环境之一是BusyBox(除了不能指定备份扩展外,其工作方式与GNU / Linux一样适用于-i )。

正如伊斯梅尔build议的,

由于perl在任何地方都可用,我只要做perl -pi -es,foo,bar,g target.file

这似乎是一个更好的解决scheme,几乎在任何情况下,脚本,别名,或其他解决scheme来处理基本不兼容的GNU / Linux和BSD / Mac之间的sed -i

Steve Powell的回答是非常正确的,在OSX和Linux(Ubuntu 12.04)上查阅MAN的页面,突出了在两个操作系统中就地使用sed的不兼容性。

JFYI,使用Linux版本的sed时,-i和任何引号(表示一个空文件扩展名)之间应该没有空格,因此

sed Linux手册页

 #Linux sed -i"" 

sed OSX手册页

 #OSX (notice the space after the '-i' argument) sed -i "" 

我在一个脚本中使用了一个别名'd命令和一个bash'if'中' uname '的OS名输出。 尝试在variables中存储与操作系统相关的命令string在解释引号时被命中并错过。 为了扩展/使用脚本中定义的别名,需要使用“ shopt -s expand_aliases ”。 shopt的用法在这里处理。

-i选项不是POSIX Sed的一部分。 更便携的方法是在Ex模式下使用Vim:

 ex -sc '%s/alfa/bravo/|x' file 
  1. %select所有行

  2. 取而代之

  3. 保存并closures

我遇到了这个问题。 唯一的快速解决scheme是将mac中的sedreplace为gnu版本:

 brew install gnu-sed 

如果您需要在bash脚本中就地执行sed ,并且您不想使用.bkp文件创build就地,并且您有办法检测操作系统(例如使用ostype.sh ),那么下面这个用bash shell内置的eval应该可以工作:

 OSTYPE="$(bash ostype.sh)" cat > myfile.txt <<"EOF" 1111 2222 EOF if [ "$OSTYPE" == "osx" ]; then ISED='-i ""' else # $OSTYPE == linux64 ISED='-i""' fi eval sed $ISED 's/2222/bbbb/g' myfile.txt ls # GNU and OSX: still only myfile.txt there cat myfile.txt # GNU and OSX: both print: # 1111 # bbbb # NOTE: # if you just use `sed $ISED 's/2222/bbbb/g' myfile.txt` without `eval`, # then you will get a backup file with quotations in the file name, # - that is, `myfile.txt""` 

你可以用海绵。 海绵是一个旧的unix程序,在moreutils软件包中find(包括ubuntu和debian,以及mac中的自制软件)。

它将缓冲来自pipe道的所有内容,等待pipe道closures(可能意味着input文件已经closures),然后覆盖:

从手册页 :

概要

sed'…'文件| grep'…'| 海绵文件

以下在Linux和OS X上适用于我:

sed -i' ' <expr> <file>

例如一个包含aaabbaaba的文件

sed -i' ' 's/b/c/g' f

在Linux和Mac上都会产生aaaccaaca 。 请注意, 包含空格的引号string在-i和string之间没有空格 。 单引号或双引号都可以工作。

在Linux上,我在Ubuntu 14.04.4下使用bash 4.3.11版本,在OS X 10.11.4 El Capitan(Darwin 15.4.0)下使用Mac版本3.2.57。