意外的就地 sed 行为

意外的就地 sed 行为

在尝试编写 sed 单行代码来替换任一实例时

infra/helm/*/charts/*

或者

infra/helm/*/charts/

在包含“infra/helm/*/charts/*”、换行符和另一行文本的文件中,如下所示

infra/helm/*/charts/*
infra/helm/*/manifests/

我成功检测到这些模式并使用这行代码在普通 zsh (版本:zsh 5.7.1 (x86_64-apple-darwin19.0))终端窗口中替换它们

sed -E $'s/infra\\/helm\\/\\*\\/charts\\/(\\*)\*/infra\\/helm\\/\\*\\/charts\\/\\*\\\ninfra\\/helm\\/\\*\\/manifests\\//' myfile

在将 '-i' 标志引入 (GNU) sed 时,我遇到了奇怪的行为变化。当我使用这个标志运行完全相同的行时

(IE

sed -iE $'s/infra\\/helm\\/\\*\\/charts\\/(\\*)\*/infra\\/helm\\/\\*\\/charts\\/\\*\\\ninfra\\/helm\\/\\*\\/manifests\\//' datfile

我发现该文件没有被修改。通常我会认为这是由于文件权限的某些特殊性或通过调用脚本而不是直接终端条目生成的进程造成的,但奇怪的是,我已经确认

sed -iE $'s/infra\\/helm\\/\\*\\/charts\\/\\*/infra\\/helm\\/\\*\\/charts\\/\\*\\\ninfra\\/helm\\/\\*\\/manifests\\//' datfile

效果很好。 (为了避免眼睛疲劳,这一行唯一的区别是它接受

infra/helm/*/charts/*

作为模式匹配,而不接受

infra/helm/*/charts/

有谁熟悉这可能是为什么? FWIW,我已经确认无论我使用上述 zsh 版本作为解释器,这种行为仍然存在,或者 GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin19) Copyright (C) 2007 Free Software Foundation, Inc.作为备选。找到一些解决方法应该不会太难,但我想提高我的 sed 技能,因此了解为什么会发生这种情况对我来说非常有价值。

我附上了运行信息的转储

strings $(which sed) 

以下

$FreeBSD: src/usr.bin/sed/compile.c,v 1.28 2005/08/04 10:05:11 dds Exp $
$FreeBSD: src/usr.bin/sed/main.c,v 1.36 2005/05/10 13:40:50 glebius Exp $
$FreeBSD: src/usr.bin/sed/misc.c,v 1.10 2004/08/09 15:29:41 dds Exp $
$FreeBSD: src/usr.bin/sed/process.c,v 1.39 2005/04/09 14:31:41 stefanf Exp $

答案1

GNU sed 的-i选项采用一个可选参数,它是用于备份的后缀。因此sed -iE … datfile会导致旧版本的文件另存为datfileE.它与您的期望不匹配,因为您没有传递该-E选项,因此正则表达式被解析为 BRE 而不是 ERE。

解决方法是单独传递选项:sed -i -E …sed -E -i …。 (-Ei如果你讨厌下一个阅读你代码的人,也可以。)

或者,传递备份后缀 ( sed -E -i.bak …),这使您的脚本既可以与 FreeBSD sed 一起使用,也可以与 GNU sed 一起使用。该后缀对于 BSD sed 是必需的,因为它的-i选项具有强制参数,并且必须与选项位于同一命令行参数中(-i和之间没有空格.bak),以便 GNU sed 将其视为可选参数,-i而不是单独的参数sed。这会产生创建备份文件的副作用。

相关内容