我现在正在搜索几天,试图找出为什么我的yaml解析器(使用PyYaml)没有保存回YAML,因为它处于原始状态。
YAML中的原始行是:
healthcheck:
test: ["CMD-SHELL", "[ x\"`curl -k --silent -w '%{http_code}' https://localhost:4433 | grep 401`\" = x\"\" ] && exit 1 || exit 0"]
interval: 30s
但新行(只是加载文件并再次保存):
healthcheck:
interval: 30s
test:
- CMD-SHELL
- '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 | grep 401`"
= x"" ] && exit 1 || exit 0'
这里有两个问题: 1)"测试"值变为列表而不是1行键值对。 2)这里实际上有3个新行,
a) -CMD-SHELL
b)- '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 | grep 401`"
c)= x"" ] && exit 1 || exit 0'
所以另一个问题是,为什么第三行从第二行被打破了? (如果我显示空格,你会看到在第二行的末尾它有LF 然后开始第三行
答案 0 :(得分:1)
我认为您可能对YAML语法有一些误解。这样:
test: ["this", "is", "a", "list"]
完全相同:
test:
- this
- is
- a
- list
而且:
- "This is a string value"
完全等同于:
- "This is a
string value"
如果我将您的示例放入文件data.yml
:
$ cat data.yml
healthcheck:
test: ["CMD-SHELL", "[ x\"`curl -k --silent -w '%{http_code}' https://localhost:4433 | grep 401`\" = x\"\" ] && exit 1 || exit 0"]
interval: 30s
然后用PyYAML解析它:
>>> import yaml
>>> with open('data.yml') as fd:
... data = yaml.load(fd)
...
我得到以下Python数据结构:
>>> pprint.pprint(data)
{'healthcheck': {'interval': '30s',
'test': ['CMD-SHELL',
'[ x"`curl -k --silent -w \'%{http_code}\' https://localhost:4433 | grep 401`" = x"" ] && exit 1 || exit 0']}}
如果我使用PyYAML转储它,我得到:
>>> print yaml.dump(data)
healthcheck:
interval: 30s
test: [CMD-SHELL, '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433
| grep 401`" = x"" ] && exit 1 || exit 0']
......看起来很好。我可以请求更详细的列表语法,在这种情况下,我会得到您在示例中显示的内容:
>>> print yaml.dump(data, default_flow_style=False)
healthcheck:
interval: 30s
test:
- CMD-SHELL
- '[ x"`curl -k --silent -w ''%{http_code}'' https://localhost:4433 | grep 401`"
= x"" ] && exit 1 || exit 0'
...它将解析与原始文档完全相同的Python数据结构。除了"看起来不同",实际数据是相同的。
答案 1 :(得分:0)
PyYAML并不擅长保存往返(加载,修改,安全)的样式,它实际上不能通过使用其加载/转储参数来保留您的输入。为此,您需要修改PyYAML解析器。
这就是在ruamel.yaml
(免责声明:我是该软件包的作者)中所做的,这是专为支持此类程序化往返(包括保留评论)而开发的:
import sys
import ruamel.yaml
from pathlib import Path
yaml_file = Path('test.yaml')
out_file = Path('out.yaml')
yaml = ruamel.yaml.YAML()
yaml.width = 2048
yaml.preserve_quotes = True
data = yaml.load(yaml_file)
yaml.dump(data, out_file)
这会为您提供out.yaml
与test.yaml
完全相同的内容。
默认宽度(80)会像在PyYAML中那样包裹你的线,因此将它设置为比你的最大长度线长的东西。 preserve_quotes
是必要的,否则"CMD-SHELL"
中多余的引号会被删除。
上面假设Python 3(对于pathlib),如果你仍然运行Python 2,你可以提交一个正确打开的普通文件句柄:
with open('test.yaml') as fp:
data = yaml.load(fp)
with open('out.yaml', 'w') as fp:
yaml.dump(data, fp)