我有 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