Macos sed-i用于就地编辑的命令,可与GNU sed和BSD/OSX一起使用

Macos sed-i用于就地编辑的命令,可与GNU sed和BSD/OSX一起使用,macos,sed,gnu,inplace-editing,Macos,Sed,Gnu,Inplace Editing,我有一个makefile(为Linux上的gmake开发),我正试图将它移植到MacOS,但似乎sed不想合作。我要做的是使用GCC自动生成依赖项文件,然后使用sed稍微调整它们。生成文件的相关部分: $(OBJ\u DIR)/%.d:$(SRC\u DIR)/%.cpp $(CPPC)-MM-MD$

我有一个makefile(为Linux上的
gmake
开发),我正试图将它移植到MacOS,但似乎
sed
不想合作。我要做的是使用
GCC
自动生成依赖项文件,然后使用
sed
稍微调整它们。
生成文件的相关部分

$(OBJ\u DIR)/%.d:$(SRC\u DIR)/%.cpp
$(CPPC)-MM-MD$<-o$@
sed-i的| \(.*)\.o:|$(OBJ\u DIR)/\1.o$(OBJ\u DIR)/\1.d$(TEST\u OBJ\u DIR)/\1\u utest.o:'$@
虽然这在GNU/Linux下运行没有问题,但在尝试在MacOS上构建时,我会遇到如下错误:

sed:1:“测试/obj/equipmentConta…”:未定义的标签“est/obj/equipmentContainer\u utest.d”
sed:1:“test/obj/dice_utest.d”:未定义的标签“est/obj/dice_utest.d”
sed:1:“test/obj/color-string_…”:未定义的标签“est/obj/color-string_utest.d”
似乎
sed
正在切掉一个字符,但我看不出解决方案。

处理
-I
参数的方式与版本不同

通过以下方式添加
-e
,您可以生成一个可能对这两者都“起作用”的命令:

#vv
sed-i-e的| \(.*)\.o:|$(OBJ\u DIR)/\1.o$(OBJ\u DIR)/\1.d$(TEST\u OBJ\u DIR)/\1\u utest.o:'$@
OSX
sed-i
-i
之后的下一个内容解释为就地编辑的备份副本的文件扩展名。(Linux版本仅在
-i
和扩展名之间没有空格时才执行此操作。)显然,使用此操作的一个副作用是,您将获得一个备份文件,其中
-e
作为扩展名,这可能是您不想要的。
有关详细信息,请参阅此问题的其他答案,以及可以替代的更清洁的方法

您看到的行为是因为OS X
sed
s | | |
作为扩展名(!)使用,然后将下一个参数解释为命令-在本例中,它以
t
开始,该
sed
将目标标签识别为参数的标签命令的分支-因此您会看到错误

如果您创建了一个文件
test
,则可以重现错误:

$sed-i的| x | y |测试
sed:1:“测试”:未定义的标签“est”
实际上,正在做

sed-i-e“s/blah/blah/”文件
在MacOS中也无法实现您的期望。而是创建扩展名为
-e
的备份文件

MacOS的正确命令是

sed-i”“-e”s/blah/blah/“文件
在Linux上,删除
-i
”之间的空格(请参阅)

sed-i”“-e”s/blah/blah/“文件

我也遇到了这个问题,并想到了以下解决方案:

darwin=false;
中的大小写“`uname`”
达尔文*)达尔文=真;;
以撒
如果是$darwin;然后
sedi=“/usr/bin/sed-i”
其他的
sedi=“sed-i”
fi
$sedi's/foo/bar/'/home/foobar/bar
为我工作;-),YMMV


我在一个多操作系统团队工作,ppl构建在Windows、Linux和OS X上。一些OS X用户抱怨,因为他们遇到了另一个错误——他们安装了sed的GNU端口,所以我必须指定完整路径

这并不是对这个问题的完全回答,但我们可以通过它获得与linux相当的行为

brew安装gnu sed
#添加到.bashrc/.zshrc
export PATH=“/usr/local/opt/gnu-sed/libexec/gnubin:$PATH”

(以前有一个
——使用默认名称
选项
brew安装gnu sed
,但最近已被删除)

我已更正@thecarpy发布的解决方案:

下面是一个适用于
sed-i
的跨平台解决方案:

sedi(){
案件$(联埃特派团)
达尔文*)sedi=('-i'');;
*)sedi='-i';;
以撒
LC_ALL=C sed“${sedi[@]}”“$@”
}

目前公认的答案在两个非常重要的方面存在缺陷

  • 对于BSD sed(OSX版本),
    -e
    选项被解释为 文件扩展名,因此创建了带有
    -e
    分机

  • 按照建议测试darwin内核不是一个可靠的方法 由于GNU或BSD sed可以 可以出现在任何数量的系统上

  • 更可靠的测试是简单地测试
    --version
    选项,该选项仅在sed的GNU版本中可用

    sed--version>/dev/null 2>&1
    
    一旦确定了sed的正确版本,我们就可以用正确的语法执行该命令

    -i选项的GNU sed语法:

    sed-i--“$@”
    
    -i选项的BSD sed语法:

    sed-i”““$@”
    
    最后,将所有功能整合到一个跨平台功能中,以执行就地编辑:

    sedi(){
    sed--version>/dev/null 2>&1&&sed-i--“$@”sed-i“$@”
    }
    
    用法示例:

    sedi's/old/new/g''some_file.txt'
    
    此解决方案已经在OSX、Ubuntu、Freebsd、Cygwin、CentOS、Red Hat Enterprise和Msys上进行了测试

    为问题[1]提供了一个很好的解释,但正如他所说的那样,解决方案可能会产生不必要的副作用

    以下是无副作用的解决方案:

    警告:单独解决
    -i
    语法问题(如下所示)可能还不够,因为GNU
    sed
    和BSD/macOS
    sed
    之间存在许多其他差异(有关全面的讨论,请参阅我的)


    使用
    -i
    的解决方法:临时创建备份文件,然后将其清理: 使用非空后缀(备份文件文件扩展名)选项参数(不是空字符串的值),您可以通过将后缀直接附加到
    -i
    选项,以一种既适用于BSD/macOS
    sed
    又适用于GNU
    sed
    的方式使用
    -i

    这可用于创建bac