【问题标题】:How to prevent yq removing comments and empty lines?如何防止 yq 删除评论和空行?
【发布时间】:2019-12-28 20:02:27
【问题描述】:

这里Edit yaml objects in array with yq. Speed up Terminalizer's terminal cast (record)问了怎么用yq编辑yaml。我收到了最好的答案。但默认情况下yq 会删除 cmets 和空行。如何防止这种行为?

input.yml

# Specify a command to be executed
# like `/bin/bash -l`, `ls`, or any other commands
# the default is bash for Linux
# or powershell.exe for Windows
command: fish -l

# Specify the current working directory path
# the default is the current working directory path
cwd: null

# Export additional ENV variables
env:
  recording: true

# Explicitly set the number of columns
# or use `auto` to take the current
# number of columns of your shell
cols: 110

执行

yq -y . input.yml

结果

command: fish -l
cwd: null
env:
  recording: true
cols: 110

【问题讨论】:

  • yq的开发者好像还没有添加这个功能-github.com/mikefarah/yq/issues/19
  • Kyb - 看了几个 yaml2json 工具后,我得出的初步结论是,不仅任何此类工具都没有解决问题,而且通用和可逆解决方案的难度大概是FOSS的范畴之外了。换句话说,您可能会更幸运地直接修改 YAML。
  • @peak,我也发现了。 sed 是一个超级通用的工具。
  • 问题是大多数这样的工具不能直接处理文本;它们使用由解析文本生成的抽象语法树,并且在解析过程中通常会删除 cmets。一般来说,如果输出与输入不同,您会在哪里“重新插入”任何已保存的 cmets?

标签: comments jq yq


【解决方案1】:

在某些有限的情况下,您可以将 diff/patch 与 yq 一起使用。
例如,如果input.yml 包含您的输入文本,则命令

$ yq -y . input.yml > input.yml.1
$ yq -y .env.recording=false input.yml > input.yml.2
$ diff input.yml.1 input.yml.2 > input.yml.diff
$ patch -o input.yml.new input.yml < input.yml.diff

创建一个文件 input.yml.new 保留 cmets 但 录音改为假:

# Specify a command to be executed
# like `/bin/bash -l`, `ls`, or any other commands
# the default is bash for Linux
# or powershell.exe for Windows
command: fish -l

# Specify the current working directory path
# the default is the current working directory path
cwd: null

# Export additional ENV variables
env:
  recording: false

# Explicitly set the number of columns
# or use `auto` to take the current
# number of columns of your shell
cols: 110

【讨论】:

  • 感谢这个想法。我使用了最近的yq 4.2.0 版,这是向前迈出的一大步(对于那些使用jq 并且该版本在保留 cmets 方面没有问题。但是,我在保留空白行时遇到了问题,我能够用 diff 的 -B 选项规避。使用一些 bashisms,我可以把它作为一个单行:diff -B "$src_file" &lt;(yq eval "$eval_line" "$src_file") | patch -o - "$src_file"