在Linux和Mac上是否都可以调用sed在没有备份的情况下进行就地编辑?虽然OS X附带的BSD sed似乎需要sed -i "…,但GNU sed Linux发行版通常会将引号解释为空的输入文件名(而不是备份扩展名),并且需要sed -i…。
是否有适用于这两种风格的命令行语法,以便我可以在两个系统上使用相同的脚本?
在Linux和Mac上是否都可以调用sed在没有备份的情况下进行就地编辑?虽然OS X附带的BSD sed似乎需要sed -i "…,但GNU sed Linux发行版通常会将引号解释为空的输入文件名(而不是备份扩展名),并且需要sed -i…。
是否有适用于这两种风格的命令行语法,以便我可以在两个系统上使用相同的脚本?
当前回答
你可以用海绵。海绵是一个老的unix程序,在moreutils包中找到(在ubuntu和debian中都有,在mac的homebrew中也有)。
它会缓冲管道中的所有内容,直到管道关闭(可能意味着输入文件已经关闭),然后覆盖:
从手册页:
剧情简介 sed的……' file | grep '…|海绵文件
其他回答
以下是我在Linux和OS X上的工作:
Sed -i' ' <expr> <文件>
例如,对于包含aaabbaaba的文件f
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。
我遇到了这个问题。唯一快速的解决方案是将mac中的sed替换为gnu版本:
brew install gnu-sed
正如Noufal Ibrahim所问的,为什么不能使用Perl?任何Mac都会有Perl,而且很少有Linux或BSD发行版在基本系统中不包含某些版本的Perl。BusyBox是唯一可能缺少Perl的环境之一(对于-i,它的工作方式与GNU/Linux类似,只是不能指定备份扩展)。
正如ismail所建议的,
由于perl在任何地方都可用,我只是做perl -pi -e s,foo,bar,g target.file
在处理sed -i在GNU/Linux和BSD/Mac之间根本不兼容的问题时,这似乎是一个比脚本、别名或其他变通方法更好的解决方案。
如果你真的想用“简单”的方式使用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文件。
如果你需要在bash脚本中执行sed in-place,并且你不希望in-place的结果是.bkp文件,并且你有一种方法来检测os(比如,使用ostype.sh),那么下面的bash shell内置eval的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""`