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

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


当前回答

以下是我在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。

其他回答

你可以用海绵。海绵是一个老的unix程序,在moreutils包中找到(在ubuntu和debian中都有,在mac的homebrew中也有)。

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

从手册页:

剧情简介 sed的……' file | grep '…|海绵文件

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

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

sed Linux手册

#Linux
sed -i"" 

and

药效发作

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

我在一个脚本中通过使用alias'd命令和bash 'if'中的'uname'的OS-name输出来解决这个问题。在解释引号时,试图将依赖于操作系统的命令字符串存储在变量中是错误的。为了扩展/使用脚本中定义的别名,必须使用'shopt -s expand_aliases'。这里讨论Shopt的用法。

以下是我在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。

如果你真的想用“简单”的方式使用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文件。

下面是另一个在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

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