sed就地标志,适用于Mac(BSD)和Linux

时间:2011-04-17 14:59:50

标签: linux macos sed bsd

是否有sed todo就地编辑的调用而没有可在Linux和Mac上运行的备份?虽然OS X附带的BSD sed似乎需要sed -i '' …,但GNU sed Linux发行版通常会将引号解释为空输入文件名(而不是备份扩展名),以及需要sed -i …代替。

是否有任何命令行语法适用于这两种风格,所以我可以在两个系统上使用相同的脚本?

14 个答案:

答案 0 :(得分:164)

如果你真的只想使用sed -i'简单'方式,那么下面的内容适用于GNU和BSD / Mac sed

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

请注意缺少空间和点。

证明:

# 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个文件。

答案 1 :(得分:97)

这适用于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上你

  • 无法使用sed -i -e,因为备份文件的扩展名将设置为-e
  • 出于同样的原因无法使用sed -i'' -e - 它需要-i''之间的空格。

答案 2 :(得分:40)

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

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

然后你的BSD sed将被GNU sed替换。

或者,您可以在没有默认名称的情况下安装,但随后:

  • 安装gnu-sed
  • 后,按照说明更改PATH
  • 根据您的系统,检查您的脚本以选择gsed或sed

答案 3 :(得分:17)

没有办法让它发挥作用。

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

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

这适用于

答案 4 :(得分:14)

正如Noufal Ibrahim所问,你为什么不能使用Perl?任何Mac都有Perl,并且很少有Linux或BSD发行版在基本系统中不包含某些版本的Perl。可能实际上缺少Perl的唯一环境之一是BusyBox(其作用类似-i的GNU / Linux,但不能指定备份扩展名。)

正如ismail建议的那样,

  

由于perl随处可用,我只需perl -pi -e s,foo,bar,g target.file

这似乎是一个比脚本,别名或其他变通方法更好的解决方案来处理GNU / Linux和BSD / Mac之间sed -i的基本不兼容性。

答案 5 :(得分:12)

答案: 否。

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

显然没有办法让sed -i在MacOS和Linuces上一致地工作。

我的建议,值得的是,不要使用sed(具有复杂的故障模式)更新到位,而是生成新文件并在之后重命名。换句话说:避免-i

答案 6 :(得分:8)

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

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

  2. s替换

  3. x保存并关闭

答案 7 :(得分:6)

Steve Powell's answer非常正确,在OSX上查阅MAN页面,Linux(Ubuntu 12.04)强调了两个操作系统中“就地”sed使用的兼容性。

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

sed Linux Man Page

#Linux
sed -i"" 

sed OSX Man page

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

我通过在bash'if'中使用alias'd命令和' uname '的操作系统名称输出来编写脚本。在解释引号时,试图在变量中存储依赖于操作系统的命令字符串。为了扩展/使用脚本中定义的别名,必须使用' shopt -s expand_aliases '。 shopt的用法由here处理。

答案 8 :(得分:4)

这是另一个可在Linux和macOS上运行的版本,无需使用eval,也无需删除备份文件。它使用Bash数组存储sed参数,比使用eval更干净:

# Default case for Linux sed, just use "-i"
sedi=(-i)
case "$(uname)" in
  # For macOS, use two parameters
  Darwin*) sedi=(-i "")
esac

# Expand the parameters in the actual call to "sed"
sed "${sedi[@]}" -e 's/foo/bar/' target.file

这不会创建备份文件,也不会创建带有引号的文件。

答案 9 :(得分:1)

我遇到了这个问题。唯一的快速解决方案是将mac中的sed替换为gnu版本:

brew install gnu-sed

答案 10 :(得分:1)

如果您需要在sed脚本中就地bash,并且您不希望就地生成.bkp文件,并且您有办法检测操作系统(比如,使用ostype.sh), - 然后内置bash内置eval shell的hack应该可以正常工作:

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""`

答案 11 :(得分:0)

你可以用海绵。 Sponge是一个旧的unix程序,可以在moreutils包中找到(在ubuntu和debian中都可以,在mac中自制)。

它会缓冲管道中的所有内容,等到管道关闭(可能意味着输入文件已经关闭),然后覆盖:

来自man page

  

概要

     

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

答案 12 :(得分:0)

适用于 GNU 系统和 OSX 的可移植脚本:

if [[ $(uname) == "Darwin" ]]; then
    SP=" " # Needed for portability with sed
fi

sed -i${SP}'' -e "s/foo/bar/g" -e "s/ping/pong/g" foobar.txt

答案 13 :(得分:-1)

以下适用于Linux和OS X:

sed -i' ' <expr> <file>

e.g。对于包含f

的文件aaabbaaba

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

在Linux和Mac上都会产生aaaccaaca。请注意,-i和字符串之间有一个带引号的字符串,其中包含空格无空格。单引号或双引号都有效。

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