是否可以在 sed 中同时使用选项 -i 和 -E ?

是否可以在 sed 中同时使用选项 -i 和 -E ?

我有一个像这样的文件

public class Constants {
    public static final String PACKAGE_VERSION = '1.24.0.1';
}

我正在执行脚本

sed -E "/PACKAGE_VERSION/s/\'([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\'/\'1.24.0.2\'/g" force-app/main/default/classes/Constants.cls > temp.cls
mv temp.cls force-app/main/default/classes/Constants.cls

将字符串“1.24.0.1”替换为“1.24.0.2”

这可以用一行来完成吗?我应该使用awk而不是sed内联编辑文件吗?

当我尝试执行命令时

sed -iE "/PACKAGE_VERSION/s/\'([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\'/\'1.24.0.3\'/g" force-app/main/default/classes/Constants.cls 

创建文件 Constants.clsE,而不是对当前文件进行内联修改,并且新文件没有替换。

当我尝试执行命令时

sed -Ei "/PACKAGE_VERSION/s/\'([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\'/\'1.24.0.3\'/g" force-app/main/default/classes/Constants.cls 

我收到一个错误

sed: 1: "force-app/main/default/ ...": invalid command code f

我希望该脚本可以在 MacOS 和 Linux 上运行,而无需更改脚本。

我尝试使用awk,但我不明白如何使其内联编辑文件?

当我尝试执行以下命令时

awk -v v="$version" '/PACKAGE_VERSION/{gsub(/[0-9]+(.[0-9]+){3}/,v)}1' force-app/main/default/classes/Constants.cls > force-app/main/default/classes/Constants.cls

这使我的文件空白

答案1

不同的实现sed复制了就地编辑-i的选项,但不幸的是它们之间具有不同的 API。perl

有些还添加了-E-r来支持(高级)扩展正则表达式(POSIX 或其变体),一些-R-P甚至是为了(非常)高级的类似 perl 的正则表达式(PCRE 或类似),但同样(除此之外-E将使其成为可能)到 POSIX 标准的下一个版本,并且现在在越来越多的实现中找到),没有什么通用的。

在这里,您不妨使用真实的东西并避免所有这些可移植性问题:

perl -i -pe "s{\bPACKAGE_VERSION\s*=\s*\K'\d+(\.\d+){3}'}{'1.24.0.3'}g" file

答案2

在某些 sed 中(至少自由BSD以及您在 Mac 上获得的那个),该-i选项需要强制的设置用于备份文件的后缀的参数。您可以在 shell 中编写-i.suffix, 或,或者不给出后缀。在这些中,or都会将or作为 and 的参数,而不是一个选项。-i .suffix-i ""-iE-i -EE-E-i

在其他一些 sed 中(至少GNU和 Busybox),该-i选项需要选修的后缀的参数,这样在同一命令行参数字符串中它后面的任何内容都是后缀。它通常以-i[suffix]文档形式呈现。您可以-i.suffix在 shell 中编写,或者只是-i不给出后缀。在这些中-iE仍然会产生E后缀,但-i -E可以作为两个选项。

在这两种情况下,-iE都表示使用后缀E,而在 FreeBSD/Mac 中,则-Ei ...采用以下参数作为后缀(您将 sed 程序放在问题中的后缀)。

如果您想为没有备份文件提供空后缀,那么这两种方法是不兼容的。在这种情况下,您必须了解其区别并-i "" -E与 FreeBSD/Mac 或-i -EGNU 一起使用。

或者,如果您想要备份文件或不关心,则可以使用-i.bak -E其中任何一个。 (您可以稍后删除备份文件。)

也可以看看如何使用 sed -i (就地编辑)实现可移植性?

答案3

-iE表示使用扩展名备份文件"E"。你必须使用:

sed -i.old -E ...

将文件备份filenamefilename.old.


在阅读评论和您的环境 (macOS) 的更新后,我添加了几个链接,您可以在其中找到有关sed使用的有用信息-i


另外,如果您想替换版本,可能使用以下命令更具可读性awk

awk -v v='1.24.0.2' '
  /PACKAGE_VERSION/{gsub(/[0-9]+(\.[0-9]+){3}/,v)}1
' force-app/main/default/classes/Constants.cls > file.tmp &&
  mv file.tmp force-app/main/default/classes/Constants.cls

注意:您不能使用输入文件作为目标,因为它会被截断,这就是您在帖子末尾提到的内容。临时文件用于提供帮助。

一般来说,在使用awk或时,我更喜欢使用临时文件,而sed不是它们的就地选项(对于 GNU awk)。上述命令预计适用于您的两种环境。

答案4

您可以按如下方式执行此操作。对于 macOS,该变量设置为非空值;对于其他系统,该变量设置为空值。然后,如果是 macOS,shell 扩展将扩展为带引号的空值,否则不会扩展(Linux 机器)

os=$(case $(uname) in Darwin*)  echo x;; esac)
sed -Ei ${os:+""} -e "..." file

相关内容