ChatGPT解决这个技术问题 Extra ChatGPT

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

我已成功使用以下 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 文件......

B
Benjamin W.

如果您使用 -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 -- ... 似乎工作正常。还提到了@stackoverflow.com/a/50245014/619961
D
Dennis Williamson

当您使用 -i 时,我相信在 OS X 上需要备份文件的扩展名。尝试:

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

使用 GNU sed,扩展是可选的


G
Giacomo1968

这适用于 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 是必需的)


第一个在 OSX 上不起作用(我刚刚在 10.6.8 上测试过)
对于 OS X (10.10.3) 上的我来说,第一个创建的备份文件以 -e 为后缀。不好。第二个是唯一一个在 Ubuntu 和 OS X 之间始终对我有用的东西。虽然我不想要备份文件,所以我必须在删除它之后立即运行 rm 命令。
第一行应该用空格重写以在 10.10 上工作:sed -i'' ... => sed -i '' ...
@DanielJomphe 但是添加这个空间不适用于 GNU sed
投了反对票,因为我在这上面浪费了很多时间,但它没有用。 (第一件事)。备份有效,但我想要没有,另一个答案中的 perl -i -pe 给出了:)
g
gniourf_gniourf

在 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 以检查它是否已更改。
O
Ohad Kravchick

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

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


.. 或者如果您使用自制软件,则安装 gnu-sed
谢谢@Sudar,点赞!
H
High Performance Mark

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


感谢您指出 BSD 问题-但我是 sed 文盲,只需要快速修复我的命令-快速浏览 man 并没有告诉我任何事情
@Yarin - 不,如果我快速浏览一下 man sed ,那也不会告诉你任何事情。试试看更长的时间。
大多数 SO 的答案都埋藏在一个人的某个地方,但这就是 SO 的意义——需要聪明人回答的忙碌的人
L
Lucas

Sinetris 的回答是正确的,但我将它与 find 命令一起使用以更具体地了解我想要更改的文件。一般来说,这应该有效(在 osx /bin/bash 上测试):

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

通常,在复杂项目中使用不带 findsed 效率较低。


-exec 非常好!我只是想知道最后的斜线是否真的需要
@YeLiu:没有 \ ,当我尝试这样的时候,; 被shell解释了
a
american-ninja-warrior

我不使用 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
v
v.babak

我创建了一个函数来处理 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" 是文件路径


D
Dan Kohn

正如其他答案所表明的那样,没有办法在不制作备份文件的情况下在 OS X 和 Linux 上可移植地使用 sed。所以,我改为使用这个 Ruby 单线器来做到这一点:

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

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

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

k
katopz

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

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


I
Igor Dolzhikov

这是 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 迟到总比没有好哈哈哈
a
ashokrajar
sed -ie 's/old_link/new_link/g' *

使用 gnu sed 在 BSD 和 Linux 上工作


这会在 linux 上创建另一个附加 e 的文件名
坏了,最好去掉。
它适用于 Mac 和 Linux。这个解决方案有什么问题?
不,它在 Mac BSD Sed 上不起作用——它会创建一个在文件名中添加“e”的备份文件。