高级用法
头疼的转义
YAML 本身的转义
一个比较好的答案: How do I break a string in YAML over multiple lines?
我们这里只针对性的讨论一下 '
, "
, \
和转义字符比如 \n
, \r
推荐的 yaml string 格式用 “, "
, |
这 3 种形式。
|
或者|-
是不需要考虑 yaml 转义的格式,类似 golang 中的 `- 会保留结尾空格
- 会保留换行
- 不支持转义
|
会保留最后的换行,|-
不会
"
是支持转义字符的格式- 换行会变成空格, 如果想不变成空格,需要结尾加 \
- 2连换行会变成换行,
\n
会变成换行 - 支持转义,
"
需要转义
- “ 是不支持转义的,且不支持 yaml 的一些保留字符的比如:
#
,:
等- 开头不能是
'
,"
- 不得占用 yaml 的关键字符
- 不支持转义
- 开头不能是
注: 遇事不决 hex dump
一下,各种语言的字符串变量通常还有自己的转义, print 打印出来的字符可能还会被 shell 本身处理,会让事情变得更加复杂
举一些常见的例子:
- 如果不用换行,不用转义, 建议 “
data: a'"\n\
# 00000000 61 27 22 5c 6e 5c |a'"\n\|
- 如果希望换行格式好看一些,且也不用转义的话,建议使用
|
或者|-
data: |
'
"
\n
\
# 注意双引号后面跟了 2 个空格
# 00000000 27 0a 22 20 20 0a 5c 6e 0a 5c 0a |'." .\n.\.|
data: |-
'
"
\n
\
# 注意双引号后面跟了 2 个空格
# 和上面比较最后的换行没有了
# 00000000 27 0a 22 20 20 0a 5c 6e 0a 5c |'." .\n.\|
- 如果涉及到转义的话,可以使用
"
data: "a'\"\\n\\\n"
# 00000000 61 27 22 5c 6e 5c 0a |a'"\n\.|
注: 这里解决之前一个遗留的问题:
可以参考 apache-flink-upload-rce.yml 这个 yaml 文件, 其中需要发送 multipart/form-data
的包。它的每一行是要以 \r\n
(hex 0d
0a
) 结尾的。
一个错误的写法:(可以关注其中的 0a
)
data: |-
--8ce4b16b22b58894aa86c421e8759df3
Content-Disposition: form-data; name="jarfile";filename="{{r2}}.jar"
Content-Type:application/octet-stream
{{r1}}
--8ce4b16b22b58894aa86c421e8759df3--
# 00000000 2d 2d 38 63 65 34 62 31 36 62 32 32 62 35 38 38 |--8ce4b16b22b588|
# 00000010 39 34 61 61 38 36 63 34 32 31 65 38 37 35 39 64 |94aa86c421e8759d|
# 00000020 66 33 0a 43 6f 6e 74 65 6e 74 2d 44 69 73 70 6f |f3.Content-Dispo|
# 00000030 73 69 74 69 6f 6e 3a 20 66 6f 72 6d 2d 64 61 74 |sition: form-dat|
# 00000040 61 3b 20 6e 61 6d 65 3d 22 6a 61 72 66 69 6c 65 |a; name="jarfile|
# 00000050 22 3b 66 69 6c 65 6e 61 6d 65 3d 22 7b 7b 72 32 |";filename="{{r2|
# 00000060 7d 7d 2e 6a 61 72 22 0a 43 6f 6e 74 65 6e 74 2d |}}.jar".Content-|
# 00000070 54 79 70 65 3a 61 70 70 6c 69 63 61 74 69 6f 6e |Type:application|
# 00000080 2f 6f 63 74 65 74 2d 73 74 72 65 61 6d 0a 0a 7b |/octet-stream..{|
# 00000090 7b 72 31 7d 7d 0a 2d 2d 38 63 65 34 62 31 36 62 |{r1}}.--8ce4b16b|
# 000000a0 32 32 62 35 38 38 39 34 61 61 38 36 63 34 32 31 |22b58894aa86c421|
# 000000b0 65 38 37 35 39 64 66 33 2d 2d |e8759df3--|
我们可以用 "
来表示此包。需要做的事情是:
- 转义掉其中的
"
- 正确的处理换行:
- 换行会变成空格, 如果想不变成空格,需要结尾加 \
- 2连换行会变成换行,
\n
会变成换行
推荐的写法:
data: "\
--8ce4b16b22b58894aa86c421e8759df3\r\n\
Content-Disposition: form-data; name=\"jarfile\";filename=\"{{r2}}.jar\"\r\n\
Content-Type:application/octet-stream\r\n\
\r\n\
{{r1}}\r\n\
--8ce4b16b22b58894aa86c421e8759df3--\r\n\
"
# 00000000 2d 2d 38 63 65 34 62 31 36 62 32 32 62 35 38 38 |--8ce4b16b22b588|
# 00000010 39 34 61 61 38 36 63 34 32 31 65 38 37 35 39 64 |94aa86c421e8759d|
# 00000020 66 33 0d 0a 43 6f 6e 74 65 6e 74 2d 44 69 73 70 |f3..Content-Disp|
# 00000030 6f 73 69 74 69 6f 6e 3a 20 66 6f 72 6d 2d 64 61 |osition: form-da|
# 00000040 74 61 3b 20 6e 61 6d 65 3d 22 6a 61 72 66 69 6c |ta; name="jarfil|
# 00000050 65 22 3b 66 69 6c 65 6e 61 6d 65 3d 22 7b 7b 72 |e";filename="{{r|
# 00000060 32 7d 7d 2e 6a 61 72 22 0d 0a 43 6f 6e 74 65 6e |2}}.jar"..Conten|
# 00000070 74 2d 54 79 70 65 3a 61 70 70 6c 69 63 61 74 69 |t-Type:applicati|
# 00000080 6f 6e 2f 6f 63 74 65 74 2d 73 74 72 65 61 6d 0d |on/octet-stream.|
# 00000090 0a 0d 0a 7b 7b 72 31 7d 7d 0d 0a 2d 2d 38 63 65 |...{{r1}}..--8ce|
# 000000a0 34 62 31 36 62 32 32 62 35 38 38 39 34 61 61 38 |4b16b22b58894aa8|
# 000000b0 36 63 34 32 31 65 38 37 35 39 64 66 33 2d 2d 0d |6c421e8759df3--.|
# 000000b0 0a |.|
PS:也可以写在一行,就是比较难读
PSS: 要是愿意的话,也可以用 2 连换行来表示 \n 不过也有点难看就是了 -_-
CEL 本身的转义
这里就不赘述 cel 本身的转义了,主要讨论几个在 yaml 中写 cel 的情况。最简单的方式就是 yaml 采用不需要转义的方式 “ 或者 |
- cel 也不需要转义
data: r"'\n"
# r" 支持输入不含 “ 的非转义字符串
# 00000000 27 5c 6e |'\n|
data: r'"\n'
# r' 支持输入不含 ' 的非转义字符串
# 00000000 22 5c 6e |"\n|
- yaml 不转义, CEL 转义
data: |
"'\"\r\n"
# r' 支持输入不含 ' 的非转义字符串
# 00000000 27 22 0d 0a |'"..|
正则的转义(RE)
CEL 支持输入正则,来使用 match
方法等,不幸的是正则也需要转义。推荐:
- yaml 采用不需要转义的方式 “ 或者
|
- cel 也采用不需要转义的方式
r'
或者r"
一些例子:
- 正则不转义
data: r'aa'.matches(a)
# golang:
# a := "aa" 匹配成功
- 正则转义
data: r'\r\n'.match(a)
# golang
# a := "\r\n" 匹配成功
data: |
r'\\r'.match(a)
# golang:
# a := `\r` 匹配成功
一个复杂的例子:
data: |
"product:\\['c=\"a\"'\\]".matches(a)
# golang:
# a:= `product:['c="a"']` 匹配成功
思路讲解:
- 考虑正则应该如何写, 该例子需要转义
[
:product:\['c="a"'\]
- 考虑 cel 转义, 因为含有
'
"
, 所以必须要转义, 选择"
的方式,需要转义"
和\
- 首先转义
\
:product:\\['c="a"'\\]
- 然后转义
"
:product:\\['c=\"a\"'\\]
- 最后用双引包裹:
"product:\\['c=\"a\"'\\]".matches(a)
- 首先转义
- 考虑 yaml 转义,选择
|
不需要转义, 最终:"product:\\['c=\"a\"'\\]".matches(a)
PS(大脑升级):
就要 yaml 用 "
格式,那么会是什么样子的呢?
- 考虑正则应该如何写, 该例子需要转义
[
:product:\['c="a"'\]
- 考虑 cel 转义, 因为含有
'
"
, 所以必须要转义, 选择"
的方式,需要转义"
和\
- 首先转义
\
:product:\\['c="a"'\\]
- 然后转义
"
:product:\\['c=\"a\"'\\]
- 最后用双引包裹:
"product:\\['c=\"a\"'\\]".matches(a)
- 首先转义
- 考虑 yaml 转义,需要转义
\
,"
- 首先转义
\
:"product:\\\\['c=\\"a\\"'\\\\]".matches(a)
- 其次转义
"
:\"product:\\\\['c=\\\"a\\\"'\\\\]\".matches(a)
- 最后用
"
包裹:"\"product:\\\\['c=\\\"a\\\"'\\\\]\".matches(a)"
- 首先转义
data: "\"product:\\\\['c=\\\"a\\\"'\\\\]\".matches(a)"
# golang:
# a:= `product:['c="a"']` 匹配成功
Was this page helpful?