如何防止yq删除注释和空行?

问题描述 投票:0回答:3

这里 使用 yq 编辑数组中的 yaml 对象。加速 Terminalizer 的终端转换(记录) 我问如何用 yq 编辑 yaml。我收到了最佳答案。但默认情况下

yq
会删除注释和空行。如何防止这种行为?

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
comments jq yq
3个回答
6
投票

在某些有限的情况下,您可以将 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
并保留注释,但 录音更改为 false:

# 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

1
投票

这是对如何防止yq删除注释和空行?注释的改进。

在我的情况下,

diff -B
diff -wB
还不够,因为它仍然不保留空白行并继续生成整个文件差异作为单个块而不是许多小块。

这是输入示例(

test.yml
):

# This file is automatically generated
#

content-index:

  timestamp: 1970-01-01T00:00:00Z

  entries:

    - dirs:

        - dir: dir-1/dir-2

          files:

            - file: file-1.dat
              md5-hash:
              timestamp: 1970-01-01T00:00:00Z

            - file: file-2.dat
              md5-hash:
              timestamp:

            - file: file-3.dat
              md5-hash:
              timestamp:

        - dir: dir-1/dir-2/dir-3

          files:

            - file: file-1.dat
              md5-hash:
              timestamp:

            - file: file-2.dat
              md5-hash:
              timestamp:

如果尝试编辑字段并生成差异文件:

diff -B test.yml <(yq -y ".\"content-index\".timestamp=\"2022-01-01T00:00:00Z\"" test.yml)

它确实会删除空白行:

5,7c2
<
<   timestamp: 1970-01-01T00:00:00Z
<
---
>   timestamp: '2022-01-01T00:00:00Z'

在各处添加

null
而不是空字段,并更改其余时间戳字段(这意味着您必须使用“...”按原样保留这些字段):

17,19c8,9
<               md5-hash:
<               timestamp: 1970-01-01T00:00:00Z
<
---
>               md5-hash: null
>               timestamp: '1970-01-01T00:00:00+00:00'

-wB
标志将差异文件从单个块更改为多个块,但仍然删除空白行。

这里提到了该差异问题:https://unix.stackexchange.com/questions/423186/diff-how-to-ignore-empty-lines/423188#423188

要解决此问题,您必须将其与 grep 一起使用:

diff -wB <(grep -vE '^\s*$' test.yml) <(yq -y ".\"content-index\".timestamp=\"2022-01-01T00:00:00Z\"" test.yml)

但是它仍然删除了评论:

1,2d0
< # This file is automatically generated
< #

这是解决方案:https://unix.stackexchange.com/questions/17040/how-to-diff-files-ignoring-comments-lines-starting-with/17044#17044

所以完整的单行是:

diff -wB <(grep -vE '^\s*(#|$)' test.yml) <(yq -y ".\"content-index\".timestamp=\"2022-01-01T00:00:00Z\"" test.yml) | patch -o - test.yml 2>/dev/null

其中

2>/dev/null
代表忽略补丁警告,例如:

Hunk #1 succeeded at 6 (offset 4 lines).

为了在实际代码中避免这种情况,您可以使用

-s
标志来代替:

... | patch -s -o ...

更新

注意

这是之前的实现,在 yaml 文件中添加一行存在问题,并作为实现示例留下。在

Update 2
部分搜索更可靠的实现。

有一个更好的实现作为 GitHub Actions 管道复合操作的 shell 脚本。

GitHub 复合操作:https://github.com/andry81-devops/gh-action--accum-content

Bash 脚本(之前的实现):

实现:https://github.com/andry81-devops/gh-workflow/blob/ee5d2d5b6bf59299e39baa16bb85357cf34a8561/bash/github/init-yq-workflow.sh
使用示例:https://github.com/andry81-devops/gh-workflow/blob/9b9d01a9b60a65d6c3c29f5b4b200409fc6a0aed/bash/cache/accum-content.sh

该实现可以使用 2 个

yq
实现:

搜索:

yq_edit
yq_diff
yq_patch
功能

更新2

还有另一个关于一些更可靠的解决方法的讨论:

yq write strips completely blank lines from the output
https://github.com/mikefarah/yq/issues/515

Bash 脚本(新实现):

实现:https://github.com/andry81-devops/gh-workflow/blob/master/bash/github/init-yq-workflow.sh
使用示例:https://github.com/andry81-devops/gh-workflow/blob/master/bash/cache/accum-content.sh

# Usage example:
#
>yq_edit "<prefix-name>" "<suffix-name>" "<input-yaml>" "$TEMP_DIR/<output-yaml-edited>" \
  <list-of-yq-eval-strings> && \
  yq_diff "$TEMP_DIR/<output-yaml-edited>" "<input-yaml>" "$TEMP_DIR/<output-diff-edited>" && \
  yq_restore_edited_uniform_diff "$TEMP_DIR/<output-diff-edited>" "$TEMP_DIR/<output-diff-edited-restored>" && \
  yq_patch "$TEMP_DIR/<output-yaml-edited>" "$TEMP_DIR/<output-diff-edited-restored>" "$TEMP_DIR/<output-yaml-edited-restored>" "<output-yaml>"
#
# , where:
#
#   <prefix-name> - prefix name part for files in the temporary directory
#   <suffix-name> - suffix name part for files in the temporary directory
#
#   <input-yaml>  - input yaml file path
#   <output-yaml> - output yaml file path
#
#   <output-yaml-edited>          - output file name of edited yaml
#   <output-diff-edited>          - output file name of difference file generated from edited yaml
#   <output-diff-edited-restored> - output file name of restored difference file generated from original difference file
#   <output-yaml-edited-restored> - output file name of restored yaml file stored as intermediate temporary file

上面带有

test.yml
的示例:

export GH_WORKFLOW_ROOT='<path-to-gh-workflow-root>' # https://github.com/andry81-devops/gh-workflow

source "$GH_WORKFLOW_ROOT/bash/github/init-yq-workflow.sh"

[[ -d "./temp" ]] || mkdir "./temp"

export TEMP_DIR="./temp"

yq_edit 'content-index' 'edit' "test.yml" "$TEMP_DIR/test-edited.yml" \
  ".\"content-index\".timestamp=\"2022-01-01T00:00:00Z\"" && \
  yq_diff "$TEMP_DIR/test-edited.yml" "test.yml" "$TEMP_DIR/test-edited.diff" && \
  yq_restore_edited_uniform_diff "$TEMP_DIR/test-edited.diff" "$TEMP_DIR/test-edited-restored.diff" && \
  yq_patch "$TEMP_DIR/test-edited.yml" "$TEMP_DIR/test-edited-restored.diff" "$TEMP_DIR/test.yml" "test-patched.yml" || exit $?

优点

  • 可以恢复空白行和独立注释行:
     # ...
  • 可以恢复行尾注释:
      key: value # ...
  • 可以检测一行的删除/更改/添加。

缺点

  • 由于有猜测逻辑,可能会留下伪影或无效的更正。
  • 不恢复 yaml 数据更改的行尾注释。

0
投票

我的用例是在 docker 容器内运行 yq 映像,而没有在基础映像上安装任何 diff 命令,并且只想进行就地更新。因此,我首先用占位符标记替换了空行

sed -i '/^$/s//BLANK_LINE: BLANK_LINE/' ./$filename
执行该操作,然后用空行替换占位符
sed -i  "s/^BLANK_LINE: BLANK_LINE//g" ./$filename
。并且工作起来很有魅力

整体组合指挥:

sed -i '/^$/s//BLANK_LINE: BLANK_LINE/' ./$filename;yq -i  {{operation}}; sed -i  "s/^BLANK_LINE: BLANK_LINE//g" ./$filename ;
© www.soinside.com 2019 - 2024. All rights reserved.