带有 -i 选项的 sed 命令在 Mac 上失败,但在 Linux 上有效
Posted
技术标签:
【中文标题】带有 -i 选项的 sed 命令在 Mac 上失败,但在 Linux 上有效【英文标题】:sed command with -i option failing on Mac, but works on Linux 【发布时间】:2011-05-13 22:07:35 【问题描述】:我已成功使用以下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
来简单演示此错误。
@Dennis,上面的简单命令会导致这种情况,尽管它正在处理的数据是整个网站(我正在转换所有图像链接),包括 html 和 css 文件...
【参考方案1】:
您的 Mac 确实运行 BASH shell,但这更多的是您正在处理的 sed 实现的问题。在 Mac 上,sed 来自 BSD,与您在典型 Linux 机器上可能找到的 sed 略有不同。我建议你man sed
。
【讨论】:
感谢您指出 BSD 问题 - 但我是 sed 文盲,只需要快速修复我的命令 - 快速浏览一下 man 并没有告诉我任何信息 @Yarin -- 不,如果我快速浏览一下 man sed,那也不会告诉您任何信息。试试看更长的时间。 大多数 SO 的答案都埋藏在一个人的某个地方,但这就是 SO 的意义——需要聪明人回答的忙碌的人【参考方案2】:如果您使用 -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' *
【讨论】:
我遇到了同样的问题。感谢您提供此解决方案。但是在我尝试使用“man sed”来查找“-i”的描述的地方,没有任何关于使用 -i '' 忽略备份的内容。这是我的第一个责备。其次,当出现错误“命令需要\后跟文本”时,为什么不直接告诉我们它需要选项'-i'的备份名称!!??这样的事情无处不在:你得到一个错误,但不知道为什么会出错,然后你搜索手册,它什么也没解释。然后你谷歌它找到其他人也有同样的问题。我的意思是,为什么不在手册中举例呢? @lukmac 据sed
所知,您确实提供了备份后缀。备份后缀为s/old_link/new_link/g
。之后的下一个参数应该是编辑命令。因为它将命令解释为备份名称,所以它将第一个文件名作为编辑命令,但它们无效。
这会一直是个问题吗? Apple 是否可以通过某种方式使用 OSX 创建解决方法/软件包 GNU sed?或者,GNU sed 不能支持sed -i '' -e ...
?
sed -i'' -e
在 mac 10.14 上似乎无法正常工作
sed -i -- ...
似乎工作正常。还提到了@***.com/a/50245014/619961【参考方案3】:
我相信在 OS X 上,当您使用 -i 时,备份文件的扩展名是必需的。试试:
sed -i .bak 's/hello/gbye/g' *
使用 GNU sed
扩展是可选的。
【讨论】:
【参考方案4】:或者,您可以在您的 Mac 中安装 GNU 版本的 sed,称为 gsed,并使用标准 Linux 语法使用它。
为此,通过运行sudo port install gsed
使用端口安装gsed
(如果没有,请在http://www.macports.org/ 获取它)。然后,你可以运行sed -i 's/old_link/new_link/g' *
【讨论】:
.. 或者如果您使用自制软件,请安装gnu-sed
感谢@Sudar,点赞!【参考方案5】:
Sinetris 的回答是正确的,但我将它与 find
命令一起使用,以更具体地了解我想要更改的文件。一般来说,这应该可以工作(在 osx /bin/bash
上测试):
find . -name "*.smth" -exec sed -i '' 's/text1/text2/g' \;
一般来说,在复杂项目中使用sed
而不使用find
效率较低。
【讨论】:
-exec
非常好!我只是想知道最后的斜线是否真的需要
@YeLiu: 如果没有 \
,当我尝试这样时,;
会被 shell 解释【参考方案6】:
这适用于 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 是必需的)
【讨论】:
第一个在 OSX 上不起作用(我刚刚在 10.6.8 上测试过) 对于我在 OS X (10.10.3) 上的我来说,第一个创建了后缀为 -e 的备份文件。不好。第二个是唯一在 Ubuntu 和 OS X 之间对我有用的东西。不过我不想要备份文件,所以我必须在删除它之后立即运行rm
命令。
第一行应该用空格重写,以便在 10.10 上工作:sed -i'' ...
=> sed -i '' ...
@DanielJomphe 但是在 GNU sed 上添加这个空间不起作用
@marcin 第一个在 OSX 10.11.2 上也适用于我。唯一的问题是它会创建一个备份文件,之后需要将其删除。第二个看起来更好,因为我们以后不必弄清楚文件名。【参考方案7】:
sed -ie 's/old_link/new_link/g' *
使用 gnu sed 在 BSD 和 Linux 上工作
【讨论】:
这会在 linux 上创建另一个带有e
的文件名
坏了,最好去掉。
它在 Mac 和 Linux 上运行。这个解决方案有什么问题?
不,它不适用于 Mac BSD Sed - 它会创建一个备份文件,并在文件名中添加“e”。【参考方案8】:
在 Mac 上遇到同样的问题,用brew
解决了:
brew install gnu-sed
并用作
gsed SED_COMMAND
您也可以将sed
设置为gsed
的别名(如果需要):
alias sed=gsed
【讨论】:
您为什么将same answer 准确地指定为Ohad Kravchick? 这样设置别名不是个好主意 而不是别名,如相应 brew 页面中建议的那样,将其添加到路径:PATH="$(brew --prefix)/opt/gnu-sed/libexec/gnubin:$PATH" 因为我们都是懒惰的开发者,所以将这一行添加到你的~/.zshrc
或bashrc 文件中:export PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"
然后运行source ~/.zshrc
更改为你选择的rc 文件!然后运行which sed
来检查它是否被改变了。【参考方案9】:
正如其他答案所表明的那样,没有办法在不制作备份文件的情况下在 OS X 和 Linux 上可移植地使用 sed。所以,我改为使用这个 Ruby 单行代码:
ruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml
在我的例子中,我需要从 rake
任务中调用它(即,在 Ruby 脚本中),所以我使用了这个额外的引用级别:
sh %qruby -pi -e "sub(/ $/, '')" ./config/locales/*.yml
【讨论】:
【参考方案10】:以下是如何将环境变量应用到模板文件(无需备份)。
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
【讨论】:
【参考方案11】:我创建了一个函数来处理 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"
是文件路径
【讨论】:
【参考方案12】:这是 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
存在为条件并将其用作变量吗??
@perrohunter 有点晚了(只有 1 年半?),但是有可能。例如。 if type gsed &> /dev/null; then; echo "use gsed"; else; echo "use sed"; fi;
@Sinetris 迟到总比不到好哈哈哈【参考方案13】:
我不使用sed
调用sed,而是使用./bin/sed
这是我 ~/project/bin/sed
中的包装脚本
#!/bin/bash
if [[ "$OSTYPE" == "darwin"* ]]; then
exec "gsed" "$@"
else
exec "sed" "$@"
fi
不要忘记chmod 755
包装脚本。
【讨论】:
假设您事先在 Mac 上完成了brew install gnu-sed
以上是关于带有 -i 选项的 sed 命令在 Mac 上失败,但在 Linux 上有效的主要内容,如果未能解决你的问题,请参考以下文章