【问题标题】:Parse yaml file with varying number of key:values使用不同数量的键解析 yaml 文件:值
【发布时间】:2020-04-28 17:58:12
【问题描述】:

长话短说,我将使用 yq 使用 bash 解析目录中的 yaml 文件。我的 yaml 文件可能如下所示:

CLIENT_FIRST_NAME: bob
CLIENT_LAST_NAME: smith

或者

CLIENT_FIRST_NAME: bob
CLIENT_LAST_NAME: smith
CLIENT_MIDDLE_NAME: michael

所以我使用 do 循环遍历每个文件并将变量设置为值 例如:

for f in $FILES
do
  FIRSTNAME=$(yq r $f CLIENT_FIRST_NAME)
  LASTNAME=$(yq r $f CLIENT_LAST_NAME)
add client --firstname=${FIRSTNAME} --lastname=${LASTNAME}
done

但有时我会有那个中间名,我需要包括:

add client --firstname=${FIRSTNAME} --lastname=${LASTNAME} --middlename=${MIDDLENAME}

顺序无关紧要,我只需要考虑可能出现在需要添加到“添加客户端”命令的 yaml 中的其他字段。 yaml 中的每一行都将添加到命令中。添加的每个键都将是“添加客户端”命令的可行参数。我不必担心 yaml 中的键是否是有效参数。他们会的。

对这里未知的最佳方法感到好奇。谢谢!

【问题讨论】:

  • for f in $FILES 已经是一个严重的问题了。您不能安全地将 list 文件存储在 string 变量中。请记住,文件名可以包含空格、换行符、全局字符等;并且扩展 $FILES 正在通过字符串拆分和全局扩展运行。
  • 顺便说一句,将r 视为子命令的yq 是哪个版本?你不是说-r吗?
  • 我使用的是最新版本的yq:3.3.0。它在 README 中使用 'r' 作为有效的子命令,并且到目前为止一直有效。
  • 啊,我们使用了两个完全不同的程序,名为yq。我的答案是针对 github.com/kislyuk/yq 的版本 2.8.1 编写和测试的。

标签: bash yaml sh yq


【解决方案1】:

我假设 yq 如果找不到密钥,则什么也不返回。

我可能会根据 yq 是否返回某些东西来制作整个标志,例如

for f in "${FILES[@]}"
do
  FIRSTNAME=$(yq r "$f" CLIENT_FIRST_NAME)
  MIDDLENAME=$(yq r "$f" CLIENT_MIDDLE_NAME)
  LASTNAME=$(yq r "$f" CLIENT_LAST_NAME)

  [[ -n $MIDDLENAME ]] && MIDDLENAME="--middlename=${MIDDLENAME}"
add client --firstname="${FIRSTNAME}" --lastname="${LASTNAME}" "${MIDDLENAME}"
done

【讨论】:

  • 这缺少引号 - 考虑通过 shellcheck.net 运行它。它根本不起作用,原因与 OP 的代码不起作用的原因相同——yq 没有将r 作为子命令。 (有一个 -r 选项,我假设是 OP 的意思)。
  • mikefarah.gitbook.io/yq/commands/read 似乎暗示 'r' 是有效的,没有连字符。不过我会试一试,只是在这里吐口水。
  • 嗯。我们使用了两个完全不相关的工具,都以yq 的名义发布,我熟悉(并且正在测试)的是github.com/kislyuk/yq
【解决方案2】:

如果您只运行yq每个输入文件一次,此代码的效率会高得多,而不是每个输入文件的每个数据项运行一次。考虑:

for f in *.yml; do
  { read -r firstname; read -r middlename; read -r lastname; } < <(
    yq -r '(.CLIENT_FIRST_NAME, .CLIENT_MIDDLE_NAME // "", .CLIENT_LAST_NAME)' "$f"
  )
  add client \
    --firstname="$firstname" \
    ${middlename:+--middlename="$middlename"} \
    --lastname="$lastname"
done

阅读本文的一些注意事项:

  • bash 中的每个read 命令读取一行,而-d 不用于修改此内容。
  • 上述yq 命令输出每个数据项一行。
  • 使用// "" 会导致在找不到CLIENT_MIDDLE_NAME 时使用空字符串,而不是null
  • 如果foo 设置为非空值,${foo:+...words here...} 将扩展为 ...words here...

【讨论】:

  • .CLIENT_MIDDLE_NAME 后面的斜线在这里有什么作用?我喜欢这确实更有效,感谢它。
  • 这基本上是一个短路的“或”(与普通的 jq/yq“或”相比,它的输出为布尔值)。没有它,没有任何中间名的 YAML 文件会将null 放在该位置的输出中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-14
  • 2020-07-18
  • 1970-01-01
  • 1970-01-01
  • 2021-05-17
  • 2017-04-30
  • 1970-01-01
相关资源
最近更新 更多