使用-i选项的sed命令在Mac上失败,但适用于Linux

时间:2010-11-22 15:33:49

标签: linux macos bash sed

我已成功使用以下sed命令在Linux中搜索/替换文本:

sed -i 's/old_link/new_link/g' *

但是,当我在Mac OS X上试用它时,我得到:

  

“命令c期望\后跟文本”

我以为我的Mac运行普通的BASH shell。怎么了?

修改

根据@High Performance,这是由于Mac sed具有不同的(BSD)风格,因此我的问题是如何在BSD sed中复制此命令?

编辑:

以下是导致此问题的实际示例:

sed -i 's/hello/gbye/g' *

13 个答案:

答案 0 :(得分:332)

如果您使用-i选项,则需要为备份提供扩展程序。

如果你有:

File1.txt
File2.cfg

该命令(请注意-i''以及-e之间缺少空间,以使其适用于新版本的Mac和GNU上的内容:

sed -i'.original' -e 's/old_link/new_link/g' *

创建2个备份文件,如:

File1.txt.original
File2.cfg.original

没有可移植的方法来避免制作备份文件,因为无法找到适用于所有情况的混合sed命令:

  • sed -i -e ... - 因为它创建-e备份
  • 而无法在OS X上运行
  • sed -i'' -e ... - 在OS X 10.6上不起作用,但适用于10.9 +
  • sed -i '' -e ... - 没有使用GNU

注意鉴于没有sed命令在所有平台上运行,您可以尝试使用其他命令来实现相同的结果。

,例如perl -i -pe's/old_link/new_link/g' *

答案 1 :(得分:47)

我相信OS X时使用-i对备份文件的扩展名为 required 。尝试:

sed -i .bak 's/hello/gbye/g' *

使用GNU sed,扩展名为可选

答案 2 :(得分:46)

这适用于sed的GNU和BSD版本:

sed -i'' -e 's/old_link/new_link/g' *

或备份:

sed -i'.bak' -e 's/old_link/new_link/g' *

注意-i选项后缺少空格! (GNU sed必备)

答案 3 :(得分:23)

在Mac中遇到同样的问题并用brew解决了它:

brew install gnu-sed

并用作

gsed SED_COMMAND

您也可以将sed设置为gsed的别名(如果需要):

alias sed=gsed

答案 4 :(得分:16)

或者,您可以在Mac中安装GNU版本的sed,名为gsed,并使用标准Linux语法进行使用。

为此,请运行gsed,使用端口安装sudo port install gsed(如果您没有端口,请通过http://www.macports.org/获取)。然后,您可以运行sed -i 's/old_link/new_link/g' *

答案 5 :(得分:8)

你的Mac确实运行了一个BASH shell,但这更像是你正在处理的sed实现的问题。在Mac上,sed来自BSD,与您在典型Linux机器上可能找到的sed略有不同。我建议你man sed

答案 6 :(得分:8)

Sinetris的答案是正确的,但我使用find命令来更具体地说明我想要更改的文件。通常这应该工作(在osx /bin/bash上测试):

find . -name "*.smth" -exec sed -i '' 's/text1/text2/g' {} \;

一般情况下,在复杂项目中使用sed而不使用find效率较低。

答案 7 :(得分:1)

以下是如何将环境变量应用于模板文件(无需备份)。

1。使用{{FOO}}创建模板以便以后替换。

echo "Hello {{FOO}}" > foo.conf.tmpl

2。用FOO变量替换{{FOO}}并输出到新的foo.conf文件

FOO="world" && sed -e "s/{{FOO}}/$FOO/g" foo.conf.tmpl > foo.conf

同时使用 macOS 10.12.4 Ubuntu 14.04.5

答案 8 :(得分:1)

这是bash脚本中的一个选项:

#!/bin/bash

GO_OS=${GO_OS:-"linux"}

function detect_os {
    # Detect the OS name
    case "$(uname -s)" in
      Darwin)
        host_os=darwin
        ;;
      Linux)
        host_os=linux
        ;;
      *)
        echo "Unsupported host OS. Must be Linux or Mac OS X." >&2
        exit 1
        ;;
    esac

   GO_OS="${host_os}"
}

detect_os

if [ "${GO_OS}" == "darwin" ]; then
    sed -i '' -e ...
else
    sed -i -e ...
fi

答案 9 :(得分:1)

除了用 sed 调用 sed,我还用 ./bin/sed

这是我的 ~/project/bin/sed

中的包装脚本
#!/bin/bash

if [[ "$OSTYPE" == "darwin"* ]]; then
  exec "gsed" "$@"
else
  exec "sed" "$@"
fi

不要忘记chmod 755包装脚本。

答案 10 :(得分:0)

sed -ie 's/old_link/new_link/g' *

适用于BSD和& Linux的

答案 11 :(得分:0)

正如其他答案所示,没有办法在不制作备份文件的情况下在OS X和Linux上移植使用sed。所以,我改为使用这个Ruby单行代码来执行此操作:

ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml

在我的情况下,我需要从rake任务(即在Ruby脚本中)调用它,所以我使用了这个额外的引用级别:

sh %q{ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml}

答案 12 :(得分:0)

我创建了一个函数来处理MacOS(在MacOS 10.12上测试)与其他OS之间的sed差异:

OS=`uname`
# $(replace_in_file pattern file)
function replace_in_file() {
    if [ "$OS" = 'Darwin' ]; then
        # for MacOS
        sed -i '' -e "$1" "$2"
    else
        # for Linux and Windows
        sed -i'' -e "$1" "$2"
    fi
}

用法:

$(replace_in_file 's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"',' "./mysql/.env")

位置:

,是分母

's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"','是模式

"./mysql/.env"是文件的路径