sed - 替换值以在需要时使用引号

sed - 替换值以在需要时使用引号

我有 100 多个 jinja 模板文件,每个文件中都出现了 0-k 次“value: ...”字符串。问题是某些文件正在使用:

value: something

他们中有一些:

value: 'something'

其中一些:

value: "some other thing"

我需要所有这些看起来都一样,使用双引号。我想我会用 sed 来做到这一点:

sed -i 's/value: ['"]?(.*)['"]?/value: "\1"/g' *.j2

但正如你所看到的,我对 sed 非常讨厌,过去的两个小时只让我想用收到的无意义错误消息来破坏我的键盘,比如:未终止的“s”命令等等。

输入示例:

- param:
  name: Command
  type: String
  value: '/bin/echo'
- param:
  name: Args
  type: String
  value: Hello World
- param:
  name: Something
  type: EnvVar
  value: "PATH"

由此我需要得到:

- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

答案1

当您需要"'在表达式中使用两种形式的引号 () 时,事情就会变得棘手。首先,在您最初的尝试中,shell 将其标识's/value: ['为带引号的字符串:后一个引号不会被保留。

在这些情况下,您不必头痛,只需将 Sed 命令放入文件中即可。其内容不会受到 shell 操作。

quotes.sed:

# (1) If line matches this regex (value: '), 
# (2) substitute the first ' with " and
# (3) substitute the ' in the end-of-line with ".
/value: '/{
  s/'/"/
  s/'$/"/
}
# (4) If line matches this regex (value: [^"]), 
# (5) substitute :<space> for :<space>" and
# (6) append a " in the end-of-line.
/value: [^"]/{
  s/: /: "/
  s/$/"/
}
$ sed -Ef quotes.sed file
- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

答案2

您的sed通话有两个问题

  • 在用单引号括起来的程序['"]中,您将文字单引号作为正则表达式的一部分。sed这不起作用,因为单引号内的单引号无法转义。但是,您可以将它们表示为\x27
  • ... (.*) ...语法是扩展正则表达式语法()默认情况下表示“捕获组”。您应该使用-E的选项sed,或者将捕获组定义为\(.*\)使用基本正则表达式(但是你也需要?用类似的东西替换\{0,1\})。

以下内容在我的测试中有效:

sed -E 's/value: [\x27"]?([^\x27"]*)[\x27"]?/value: "\1"/' input.j2

答案3

使用 GNU awk 将第三个参数传递给 match() 和 gensub():

$ awk 'match($0,/(\s*value:\s*)(.*)/,a){$0=a[1] "\"" gensub(/[\047"]/,"","g",a[2]) "\""} 1' file
- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

否则使用任何 awk:

$ awk '/value:/{hd=$0; sub(/:.*/,": ",hd); gsub(/[^:]*: *[\047"]?|[\047"]$/,"");  $0=hd "\"" $0 "\""} 1' file
- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

答案4

使用 Raku(以前称为 Perl6)

一位名叫 Larry Wall 的绅士在“perl6-users”邮件列表上发布了这个简洁的引用提示([电子邮件受保护])。请参阅下面 NNTP 链接中的提示 #8:

~$ env re="\'" raku -ne 'say $0 if m/ <?after value\:\s >  \"? <{ %*ENV<re> }>?  (.+?) \"? <{ %*ENV<re> }>? $$ /;'  jinja.txt
「/bin/echo」
「Hello World」
「PATH」

上面的代码显示了正确的匹配。因此,所需要做的就是运行下面的代码:

~$ env re="\'" raku -pe 's/ <?after value\:\s >  \"? <{ %*ENV<re> }>?  (.+?) \"? <{ %*ENV<re> }>? $$ /"{$0}"/;'  jinja.txt
- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

想让你的转义更具可读性吗?不想像上面那样使用 ENV 变量?然后只需拼出您的引用字符(也来自下面 NNTP 链接中 Larry Wall 的提示 #8):

~$ raku -ne 'say $0 if m/ <?after value\:\s >  \c[QUOTATION MARK]? \c[APOSTROPHE]?  (.+?)  \c[APOSTROPHE]? \c[QUOTATION MARK]? $$ /;'  jinja.txt
「/bin/echo」
「Hello World」
「PATH」

~$ raku -pe 's/ <?after value\:\s >  \c[QUOTATION MARK]? \c[APOSTROPHE]?  (.+?)  \c[APOSTROPHE]? \c[QUOTATION MARK]? $$ /"{$0}"/;'  jinja.txt
- param:
  name: Command
  type: String
  value: "/bin/echo"
- param:
  name: Args
  type: String
  value: "Hello World"
- param:
  name: Something
  type: EnvVar
  value: "PATH"

HTH。

https://raku.org/
https://www.nntp.perl.org/group/perl.perl6.users/2020/07/msg9004.html

相关内容