bsd mac linux,关于macos:在Mac(BSD)和Linux上均可使用的sed就地标志

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

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

Perl不是一种选择吗? 您必须使用sed吗?

也许安装GNU版本并使用它!topbug.net/blog/2013/04/14/? 我先尝试一下。 再说一次,那也很烂。

@dimadima:对于浏览此问题的其他人来说,可能会很有趣,因为他们的个人脚本在OS X计算机上已损坏。 不过,就我而言,我需要一个开放源代码项目的构建系统,告诉您的用户首先安装GNU sed可能会违反此练习的初衷(以"无处不在的工作方式"修补一些文件)。

@klickverbot是的,很有道理。 我首先添加评论作为答案,然后将其删除,意识到它不是您问题的答案:)。

交叉参考:如何使用sed -i(就地编辑)实现可移植性? 在Unix和Linux Stack Exchange上。

如果您真的只想以简单的方式使用sed -i,则以下DOES在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文件。

这是要走的路。添加几个字符,并使其可移植。删除备份文件很简单(调用sed时已经有了文件名)

这在Mac上有效,但是在ubuntu 16.04上,它会将原始文件覆盖为0字节,并且还使用0字节创建了.bak文件?

值得注意的是,在macOS Sierra(可能还有更早的版本,我没有手持计算机)上,sed在用-i调用时不接受位置command自变量-必须提供另一个标志-e。因此,命令变为:sed -i.bak -e sfoobar filename

这将创建备份,而OP专门要求进行就地编辑。

因此,完整的解决方案是:sed -i.bak sfoobar file && rm file.bak

这适用于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和''之间需要一个空格。

-e做什么?

@AlexanderMills告诉sed,下一个参数是命令-也可以在此处跳过。

请注意,-i和-i在shell解析时是相同的。 sed在前两个调用中的行为不会有所不同,因为它获得了完全相同的参数。

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

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

然后,您的BSD sed将被GNU sed代替。

或者,您可以不使用默认名称进行安装,但是可以:

安装gnu-sed之后,按照说明更改PATH

请检查脚本,以根据系统在gsed或sed之间进行选择

--with-default-names已从homebrew-core中删除,有关此答案的更多信息。立即安装gnu-sed时,安装说明指定您需要将gnubin添加到PATH:PATH="usrlocaloptgnu-sedlibexecgnubin:$PATH"

没有办法使其起作用。

一种方法是使用类似以下的临时文件:

TMP_FILE=`mktemp /tmp/config.XXXXXXXXXX`

sed -e"s/abc/def/" some/file > $TMP_FILE

mv $TMP_FILE some/file

这既适用于

是否存在SOME_FILE =" $(sed -s" s / abc / def /" some / file)"的原因; echo" $ SOME_FILE">一些/文件;不会工作

看起来您将受到bash变量的最大大小的限制,不是吗?不确定它将与GBs文件一起使用。

如果要创建一个临时文件,为什么不给扩展名一个备份文件(然后可以删除它),如下面@kine所示?

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

按照ismail的建议,

Since perl is available everywhere I just do perl -pi -e s,foo,bar,g target.file

在几乎任何情况下,这似乎都是比脚本,别名或其他替代方法更好的解决方案,用于解决GNU / Linux与BSD / Mac之间sed -i的根本不兼容问题。

我喜欢这个解决方案。自2009年5月1日以来,perl是Linux Standard Base规范的一部分。refspecs.linuxfoundation.org/LSB_4.0.0/LSB-Languages/

这很容易成为便携性的最佳解决方案

答:不可以。

最初接受的答案实际上并不执行要求的操作(如注释中所述)。 (寻找file-e在我的目录中"随机"出现的原因时,我找到了这个答案。)

显然,没有任何方法可以使sed -i在MacOS和Linuces上始终如一地工作。

对于我来说,值得的建议不是使用sed(具有复杂的故障模式)就地更新,而是生成新文件并随后对其重命名。换句话说:避免使用-i。

-i选项不是POSIX Sed的一部分。 一种更便携的方法是

在Ex模式下使用Vim:

ex -sc '%s/alfa/bravo/|x' file

%选择所有行

s替换

x保存并关闭

这是另一个可在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

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

这是正确的答案。我会简化一下,但是这个想法很好用sedi=(-i) && ["$(uname)" =="Darwin" ] && sedi=(-i ) sed"${sedi[@]}" -e sfoobar target.file

好东西!不过,我更喜欢较长版本的可读性。

这是我与其他系统兼容的最佳方法。

史蒂夫·鲍威尔(Steve Powell)的答案是非常正确的,请查阅有关OSX和Linux上sed的MAN页面(Ubuntu 12.04),着重强调了这两种操作系统在"就地" sed使用中的兼容性。

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

sed Linux手册页

#Linux

sed -i""

sed OSX手册页

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

sed -i""

我通过在bash'if'中使用别名命令和OS名称输出'uname'来解决这个问题。解释引号时,尝试将依赖于OS的命令字符串存储在变量中时会遇到麻烦。为了扩展/使用脚本中定义的别名,必须使用'shopt -s expand_aliases'。 shopt的用法在这里处理。

如果您需要在bash脚本中就地执行sed,并且您不希望就地产生.bkp文件,则可以使用一种检测os的方法(例如,使用ostype.sh ),-那么使用bash shell内置eval的以下hack应该起作用:

OSTYPE="$(bash ostype.sh)"

cat > myfile.txt <

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

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

brew install gnu-sed

这将复制现有答案,并提供2015年以来的更多详细信息。

以下内容适用于Linux和OS X:

sed -i' '

例如对于包含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 OS上对我不起作用...创建了新文件,文件名末尾附加了空格

在Mac(/ usr / bin / sed)上对我也不起作用-我现在有一个额外的备份文件,文件名后附加一个空格:-(

尝试从单引号中删除空格,它对我有用。

您可以使用海绵。 Sponge是一个古老的unix程序,可在moreutils包中找到(在ubuntu和debian中都可以找到,在mac上的homebrew中都可以找到)。

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

从手册页:

Synopsis

sed '...' file | grep '...' | sponge file

好的方法–不幸的是,在原始情况下并没有真正帮助,因为诉诸sed的原因是要在客户端计算机上使用的跨平台帮助程序脚本中使用某些东西,在此脚本中您只能依赖于正在安装的系统工具。但是可能对其他人有帮助。

海绵很棒。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值