带-i选项的sed命令在Mac上失败,但在Linux上有效

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

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

然而,当我在Mac OS X上尝试它时,我得到:

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

我以为我的Mac运行一个正常的BASH shell。有什么事吗?

编辑:

根据@高性能,这是由于Mac sed是一个不同的(BSD)口味,所以我的问题是如何在BSD sed复制这个命令?

编辑:

下面是一个实际的例子:

sed -i 's/hello/gbye/g' *
306903 次浏览

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

如果你使用-i选项,你需要为备份提供一个扩展。

如果你有:

File1.txt
File2.cfg

命令(注意,在-i''之间缺少空格,以使其在新版本的Mac和GNU上工作):

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

创建2个备份文件,例如:

File1.txt.original
File2.cfg.original

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

  • sed -i -e ... -不能在OS X上工作,因为它创建了-e备份
  • sed -i'' -e ... -不能在OS X 10.6上工作,但可以在10.9+上工作
  • sed -i '' -e ... -不能在GNU上工作

请注意假设没有sed命令可以在所有平台上运行,您可以尝试使用另一个命令来实现相同的结果。

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

我相信在OS X上使用-i时,备份文件的扩展名是要求。试一试:

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

使用GNU sed扩展为可选

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

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

Sinetris的答案是正确的,但我将此与find命令一起使用,以更具体地说明我想更改哪些文件。一般来说,这应该工作(在osx /bin/bash上测试):

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

一般来说,在复杂的项目中使用sed而不使用find效率较低。

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

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

或者有备份:

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

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

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

工作在BSD和amp;Linux与gnu sed

在Mac中有同样的问题,并使用brew解决了它:

brew install gnu-sed

使用as

gsed SED_COMMAND

你也可以将sed作为别名设置为gsed(如果你想的话):

alias sed=gsed

正如其他答案所表明的那样,如果不创建备份文件,就无法在OS X和Linux之间可移植地使用sed。所以,我转而使用Ruby的一行代码来实现:

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

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

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

下面是如何将环境变量应用到模板文件(不需要备份)。

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.4Ubuntu 14.04.5

我已经创建了一个函数来处理MacOS(在MacOS 10.12上测试)和其他操作系统之间的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")

地点:

,是一个delimeter

's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"','是pattern

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

下面是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

我没有使用sed调用sed,而是使用./bin/sed

这是我的~/project/bin/sed中的包装器脚本

#!/bin/bash


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

不要忘记chmod 755包装器脚本。