我已成功使用以下 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' *
sed
将数据中的“c”视为命令。你在使用变量吗?请发布更接近实际命令和您正在处理的一些数据的内容。您可以通过执行 echo x | sed c
获得此错误的简单演示。
如果您使用 -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 ... - 在 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' *
当您使用 -i 时,我相信在 OS X 上需要备份文件的扩展名。尝试:
sed -i .bak 's/hello/gbye/g' *
使用 GNU sed
,扩展是可选的。
这适用于 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 是必需的)
rm
命令。
sed -i'' ...
=> sed -i '' ...
perl -i -pe
给出了:)
在 Mac 中遇到了同样的问题并用 brew
解决了它:
brew install gnu-sed
并用作
gsed SED_COMMAND
您也可以将 sed
设置为 gsed
的别名(如果需要):
alias sed=gsed
~/.zshrc
或 bashrc 文件中:export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
然后运行 source ~/.zshrc
更改为您选择的 rc 文件!然后运行 which sed
以检查它是否已更改。
或者,您可以在 Mac 中安装 sed 的 GNU 版本,称为 gsed,并使用标准 Linux 语法使用它。
为此,通过运行 sudo port install gsed
使用端口安装 gsed
(如果没有,请在 http://www.macports.org/ 获取)。然后,您可以运行 sed -i 's/old_link/new_link/g' *
gnu-sed
您的 Mac 确实运行 BASH shell,但这更多的是您正在处理的 sed 实现的问题。在 Mac 上,sed 来自 BSD,与您可能在典型 Linux 机器上找到的 sed 略有不同。我建议你man sed
。
Sinetris 的回答是正确的,但我将它与 find
命令一起使用以更具体地了解我想要更改的文件。一般来说,这应该有效(在 osx /bin/bash
上测试):
find . -name "*.smth" -exec sed -i '' 's/text1/text2/g' {} \;
通常,在复杂项目中使用不带 find
的 sed
效率较低。
-exec
非常好!我只是想知道最后的斜线是否真的需要
\
,当我尝试这样的时候,;
被shell解释了
我不使用 sed
调用 sed,而是使用 ./bin/sed
这是我的 ~/project/bin/sed
中的包装脚本
#!/bin/bash
if [[ "$OSTYPE" == "darwin"* ]]; then
exec "gsed" "$@"
else
exec "sed" "$@"
fi
不要忘记 chmod 755
包装脚本。
brew install gnu-sed
我创建了一个函数来处理 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")
在哪里:
,
是一个分隔符
's,MASTER_HOST.*,MASTER_HOST='"$MASTER_IP"','
是模式
"./mysql/.env"
是文件路径
正如其他答案所表明的那样,没有办法在不制作备份文件的情况下在 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.4 和 Ubuntu 14.04.5
这是 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
gsed
的存在并将其用作变量吗?
if type gsed &> /dev/null; then; echo "use gsed"; else; echo "use sed"; fi;
sed -ie 's/old_link/new_link/g' *
使用 gnu sed 在 BSD 和 Linux 上工作
e
的文件名
sed
所知,您确实提供了备份后缀。备份后缀是s/old_link/new_link/g
。之后的下一个参数应该是编辑命令。因为它将命令解释为备份名称,所以它将第一个文件名作为编辑命令,但它们无效。sed -i '' -e ...
吗?sed -i'' -e
在 mac 10.14 上似乎无法正常工作sed -i -- ...
似乎工作正常。还提到了@stackoverflow.com/a/50245014/619961