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

kli*_*bot 218 linux macos bsd sed

是否有一个sedtodo就地编辑的调用,没有可在Linux和Mac上运行的备份?虽然BSD sed随OS X似乎需要sed -i '' …,在GNU sedLinux的发行版通常都与解释的报价为空,输入文件名(而不是备份扩展),并且需要sed -i …替代.

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

kin*_*ine 189

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

sed -i.bak 's/foo/bar/' filename
Run Code Online (Sandbox Code Playgroud)

注意缺少空间和点.

证明:

# 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
Run Code Online (Sandbox Code Playgroud)

显然你可以删除.bak文件.

  • 所以完整的解决方案是:`sed -i.bak的/ foo/bar /'file && rm file.bak` (6认同)
  • 这会创建备份,而OP则专门要求进行就地编辑. (4认同)
  • 这是要走的路.添加几个字符,它是可移植的.删除备份文件很简单(调用`sed`时已经有了文件名) (2认同)
  • 值得注意的是,在 macOS Sierra(可能更早的时候,我手头没有机器),当使用 `-i` 调用时,`sed` 不接受位置性 `command` 参数——它*必须*提供另一个标志,`-e`。因此,命令变为:`sed -i.bak -e 's/foo/bar/' filename` (2认同)

kli*_*bot 104

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

sed -i -e 's/foo/bar/' target.file
sed -i'' -e 's/foo/bar/' target.file
Run Code Online (Sandbox Code Playgroud)

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

sed -i '' -e 's/foo/bar/' target.file
Run Code Online (Sandbox Code Playgroud)

在OS X上你

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

  • 什么-e做什么? (2认同)
  • 注意,`-i`和`-i'`在shell解析时是相同的。sed _不能_在前两个调用中表现不同,因为它获得完全相同的参数。 (2认同)

小智 41

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

brew install gnu-sed --with-default-names
Run Code Online (Sandbox Code Playgroud)

然后你的BSD sed将被GNU sed取代.

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

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

  • --with-default-names`已从[homebrew-core中删除](https://github.com/Homebrew/homebrew-core/search?q=default-names%20created%3A2019-01-01.。 2019-01-10&unscoped_q =默认名称%20created%3A2019-01-01..2019-01-10&type = Commits),更多信息请参见[this](https://apple.stackexchange.com/a/88812)答案。现在安装“ gnu-sed”时,安装说明指定您需要将“ gnubin”添加到“ PATH”中:`PATH =“ / usr / local / opt / gnu-sed / libexec / gnubin:$ PATH” (3认同)

Ale*_*puy 17

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

正如ismail建议的那样,

因为perl在我到处都可用 perl -pi -e s,foo,bar,g target.file

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

  • 这无疑是便携性的最佳解决方案 (2认同)

ana*_*gue 16

没有办法使它工作.

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

TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX`
sed -e "s/abc/def/" some/file > $TMP_FILE
mv $TMP_FILE some/file
Run Code Online (Sandbox Code Playgroud)

这适用于两者

  • 如果您要创建临时文件,为什么不直接创建一个备份文件(然后可以删除),如下面的@kine所示? (3认同)

Ste*_*ell 12

答:没有.

最初接受的答案实际上并不符合要求(如评论中所述).(当我找到file-e在我的目录中"随机"出现的原因时,我找到了这个答案.)

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

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


小智 9

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

ex -sc '%s/alfa/bravo/|x' file
Run Code Online (Sandbox Code Playgroud)
  1. % 选择所有行

  2. s 更换

  3. x 保存并关闭


nwi*_*ler 8

这是另一个可在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
Run Code Online (Sandbox Code Playgroud)

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

  • 这是正确答案。我会稍微简化一下,但这个想法很完美 `sedi=(-i) && [ "$(uname)" == "Darwin" ] && sedi=(-i '')` `sed "${sedi[ @]}" -e 's/foo/bar/' target.file` (3认同)

Jon*_*Jon 7

适用于 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
Run Code Online (Sandbox Code Playgroud)

  • 没有理由在“Darwin”周围加上引号——它除了自身之外无法解析任何内容。然而,如果不是因为 `[[ ]]` 的特殊语义,您需要在 `$(uname)` 周围加上引号,以确保所有可能的返回值的正确行为。 (4认同)

Big*_*ich 6

史蒂夫鲍威尔的回答非常正确,在OSX和Linux(Ubuntu 12.04)上查阅MAN页面上的sed强调了两个操作系统中"就地"sed使用的兼容性.

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

sed Linux Man Page

#Linux
sed -i"" 
Run Code Online (Sandbox Code Playgroud)

sed OSX手册页

#OSX (notice the space after the '-i' argument)
sed -i "" 
Run Code Online (Sandbox Code Playgroud)

我在一个脚本中使用别名命令和bash'if'中的' uname ' 的OS名称输出.在解释引号时,试图在变量中存储依赖于操作系统的命令字符串.为了扩展/使用脚本中定义的别名,必须使用' shopt -s expand_aliases '.shopt的用法在这里处理.