sed 就地标志,适用于 Mac (BSD) 和 Linux
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5694228/
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
sed in-place flag that works both on Mac (BSD) and Linux
提问by dnadlinger
Is there an invocation of sed
todo in-place editing without backups that works both on Linux and Mac? While the BSD sed
shipped with OS X seems to need sed -i '' …
, the GNU sed
Linux distributions usually come with interprets the quotes as empty input file name (instead of the backup extension), and needs sed -i …
instead.
是否sed
可以在 Linux 和 Mac 上调用没有备份的todo 就地编辑?虽然sed
OS X 附带的 BSD似乎需要sed -i '' …
,但 GNU sed
Linux 发行版通常会将引号解释为空输入文件名(而不是备份扩展名),sed -i …
而是需要。
Is there any command line syntax which works with both flavors, so I can use the same script on both systems?
是否有任何命令行语法适用于两种风格,以便我可以在两个系统上使用相同的脚本?
采纳答案by kine
If you really want to just use sed -i
the 'easy' way, the following DOES work on both GNU and BSD/Mac sed
:
如果您真的只想使用sed -i
“简单”的方式,以下在 GNU 和 BSD/Mac 上都适用sed
:
sed -i.bak 's/foo/bar/' filename
Note the lack of space and the dot.
请注意缺少空间和点。
Proof:
证明:
# 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
Obviously you could then just delete the .bak
files.
显然,您可以删除这些.bak
文件。
回答by dnadlinger
This works with GNU sed, but not on OS X:
这适用于 GNU sed,但不适用于 OS X:
sed -i -e 's/foo/bar/' target.file
sed -i'' -e 's/foo/bar/' target.file
This works on OS X, but not with GNU sed:
这适用于 OS X,但不适用于 GNU sed:
sed -i '' -e 's/foo/bar/' target.file
On OS X you
在 OS X 上你
- can't use
sed -i -e
since the extension of the backup file would be set to-e
- can't use
sed -i'' -e
for the same reasons—it needs a space between-i
and''
.
- 无法使用,
sed -i -e
因为备份文件的扩展名将设置为-e
sed -i'' -e
出于同样的原因不能使用——它需要在-i
和之间留一个空格''
。
回答by Steve Powell
Answer:No.
回答:没有。
The originally accepted answer actually doesn't do what is requested (as noted in the comments). (I found this answer when looking for the reason a file-e
was appearing "randomly" in my directories.)
最初接受的答案实际上并没有按照要求执行(如评论中所述)。(我在寻找 afile-e
在我的目录中“随机”出现的原因时找到了这个答案。)
There is apparently no way of getting sed -i
to work consistently on both MacOS and Linuces.
显然没有办法sed -i
在 MacOS 和 Linuces 上始终如一地工作。
My recommendation, for what it is worth, is not to update-in-place with sed
(which has complex failure modes), but to generate new files and rename them afterwards. In other words: avoid -i
.
就其价值而言,我的建议不是就地更新sed
(具有复杂的故障模式),而是生成新文件并在之后重命名它们。换句话说:避免-i
。
回答by Big Rich
Steve Powell's answeris quite correct, consulting the MAN page for sed on OSX and Linux (Ubuntu 12.04) highlights the in-compatibility within 'in-place' sed usage across the two operating systems.
Steve Powell 的回答非常正确,在 OSX 和 Linux (Ubuntu 12.04) 上查阅 sed 的 MAN 页面强调了两个操作系统中“就地”sed 使用的不兼容性。
JFYI, there should be no space between the -i and any quotes (which denote an empty file extension) using the Linux version of sed, thus
JFYI,使用 Linux 版本的 sed 在 -i 和任何引号(表示空文件扩展名)之间不应该有空格,因此
#Linux
sed -i""
and
和
#OSX (notice the space after the '-i' argument)
sed -i ""
I got round this in a script by using an alias'd command and the OS-name output of 'uname' within a bash 'if'. Trying to store OS-dependant command strings in variables was hit and miss when interpreting the quotes. The use of 'shopt -s expand_aliases' is necessary in order to expand/use the aliases defined within your script. shopt's usage is dealt with here.
我通过使用别名命令和bash 'if' 中的 ' uname'的操作系统名称输出在脚本中解决了这个问题。在解释引号时,尝试将依赖于操作系统的命令字符串存储在变量中是偶然的。必须使用“ shopt -s expand_aliases”才能扩展/使用脚本中定义的别名。shopt 的用法在这里处理。
回答by analogue
There is no way to have it working.
没有办法让它工作。
One way is to use a temporary file like:
一种方法是使用临时文件,如:
TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX`
sed -e "s/abc/def/" some/file > $TMP_FILE
mv $TMP_FILE some/file
This works on both
这适用于
回答by Guillermo
You can use sponge. Sponge is an old unix program, found in moreutils package (both in ubuntu and probably debian, and in homebrew in mac).
你可以用海绵。Sponge 是一个旧的 unix 程序,可以在 moreutils 包中找到(在 ubuntu 和 debian 中,以及在 mac 中的 homebrew 中)。
It will buffer all the content from the pipe, wait until the pipe is close (probably meaning that the input file is already close) and then overwrite:
它将缓冲管道中的所有内容,等到管道关闭(可能意味着输入文件已经关闭)然后覆盖:
From the man page:
从手册页:
Synopsis
sed '...' file | grep '...' | sponge file
概要
sed '...' 文件 | grep '...' | 海绵文件
回答by Alex Dupuy
As Noufal Ibrahimasks, why can't you use Perl? Any Mac will have Perl, and there are very few Linux or BSD distributions that don't include some version of Perl in the base system. One of the only environments that might actually lack Perl would be BusyBox (which works like GNU/Linux for -i
, except that no backup extension can be specified).
正如Noufal Ibrahim 所问的,为什么不能使用 Perl?任何 Mac 都会有 Perl,而且很少有 Linux 或 BSD 发行版在基本系统中不包含某些版本的 Perl。可能实际上缺少 Perl 的唯一环境之一是 BusyBox(它的工作方式类似于 GNU/Linux for -i
,但不能指定备份扩展名)。
As ismailrecommends,
正如伊斯梅尔所建议的那样,
Since perl is available everywhere I just do
perl -pi -e s,foo,bar,g target.file
由于 perl 随处可用,我只是这样做
perl -pi -e s,foo,bar,g target.file
and this seems like a better solution in almost any case than scripts, aliases, or other workarounds to deal with the fundamental incompatibility of sed -i
between GNU/Linux and BSD/Mac.
几乎在任何情况下,这似乎都是比脚本、别名或其他解决方法更好的解决方案,以处理sed -i
GNU/Linux 和 BSD/Mac 之间的根本不兼容性。
回答by Lewy
When on OSX, I always install GNU sed version via Homebrew, to avoid problems in scripts, because most scripts were written for GNU sed versions.
在 OSX 上,我总是通过 Homebrew 安装 GNU sed 版本,以避免脚本出现问题,因为大多数脚本都是为 GNU sed 版本编写的。
brew install gnu-sed --with-default-names
Then your BSD sed will be replaced by GNU sed.
那么你的 BSD sed 将被 GNU sed 取代。
Alternatively, you can install without default-names, but then:
或者,您可以不使用默认名称进行安装,但是:
- Change your
PATH
as instructed after installinggnu-sed
- Do check in your scripts to chose between
gsed
orsed
depending on your system
PATH
安装后按照说明更改gnu-sed
- 请检查您的脚本以在您的系统之间
gsed
或sed
根据您的系统进行选择
回答by David G
The following works for me on Linux and OS X:
以下在 Linux 和 OS X 上对我有用:
sed -i' ' <expr> <file>
sed -i' ' <expr> <file>
e.g. for a file f
containing aaabbaaba
例如,对于f
包含aaabbaaba
sed -i' ' 's/b/c/g' f
sed -i' ' 's/b/c/g' f
yields aaaccaaca
on both Linux and Mac. Note there is a quoted string containing a space, with no spacebetween the -i
and the string. Single or double quotes both work.
aaaccaaca
在 Linux 和 Mac 上都能产生收益。请注意,有一个包含空格的带引号的字符串,在和字符串之间没有空格-i
。单引号或双引号都有效。
On Linux I am using bash
version 4.3.11 under Ubuntu 14.04.4 and on the Mac version 3.2.57 under OS X 10.11.4 El Capitan (Darwin 15.4.0).
在 Linux 上,我bash
在 Ubuntu 14.04.4 下使用4.3.11 版,在 OS X 10.11.4 El Capitan(达尔文 15.4.0)下使用 Mac 3.2.57 版。
回答by Steven Penny
The -i
option is not part of POSIX Sed. A more portable method would be
to use Vim in Ex mode:
该-i
选项不是POSIX Sed 的一部分。一种更便携的方法是在 Ex 模式下使用 Vim:
ex -sc '%s/alfa/bravo/|x' file
%
select all liness
replacex
save and close
%
选择所有行s
代替x
保存并关闭