如何使用shell管道更新YAML文件?

时间:2017-07-28 16:57:52

标签: json shell yaml

我正在寻找一种简单的UNIX方法,用于将使用shell脚本获取的数据保存到YAML文件中,例如,我想使用shell管道将系统中已安装的软件包列表(rpms,pypi)保存在单个YAML文件中,像:

rpm -qa |排序| some-yaml-tool manifest.yaml system.packages

预期结果将是manifest.yaml文件,如下所示:

system:
    packages:
        - xz-5.2.2-2.fc24.x86_64
        - xz-devel-5.2.2-2.fc24.x86_64

虽然我更喜欢YAML,但我不会拒绝兼容JSON的解决方案。我真的很想找到一种方法来使用大多数发行版上提供的工具,而不是需要手动安装或从非官方yum / deb存储库安装的东西。

如果该工具是智能工具,它应该能够在存在时创建文件和内部路径。

请注意,我必须从列表中删除jq工具,因为它not allow in-place editing

2 个答案:

答案 0 :(得分:1)

将包名称插入YAML文件

您根本不需要就预期用例提供就地编辑支持。注意到YAML是JSON的超集,因此jq的所有输出也是有效的YAML:

rpm -qa | sort | jq -Rn '{"system": {"packages": [inputs]}}'

将生成以下格式的输出文件:

{
  "system": {
    "packages": [
      "bar",
      "baz",
      "foo"
    ]
  }
}

......只需一次通过。为了使这个更加惯用的YAML,您可以使用PyYAML库解析一个小的Python垫片:

yaml_format() {
  python -c 'import sys, yaml; sys.stdout.write(yaml.dump(yaml.load(sys.stdin), default_flow_style=False))'
}
rpm -qa | sort | jq -Rn '{"system": {"packages": [inputs]}}' | yaml_format

...将生成以下形式的内容:

system:
  packages:
  - bar
  - baz
  - foo

就地更新JSON文件

我们假设您已经拥有一个JSON文件,其内容不是您要保留的清单。在这种情况下,明确提出的问题变得相关。安全(尽管仅限GNU)实现如下所示:

atomic_update() {
  # usage: atomic_update filename command arg1 arg2 ...
  local filename tempfile retval=0
  filename=$1; shift || return
  tempfile=$(mktemp -t -- "$filename.XXXXXX") || return
  if "$@" <"$filename" >"$tempfile"; then
    # Make a best-effort attempt to preserve permissions
    chown --reference="$filename" -- "$tempfile" &>/dev/null ||:
    chmod --reference="$filename" -- "$tempfile" &>/dev/null ||:
    mv -- "$tempfile" "$filename"
  else
    retval=$?
    rm -f -- "$tempfile"
  fi
  return "$retval"
}

rpm -qa | sort | atomic_update manifest.yml jq -Rn '.system.packages = [inputs]'

答案 1 :(得分:0)

虽然我还没有完全正常工作的解决方案,但我认为我非常接近通过json npm包找到一个。

echo "{}" > e.json
seq 3 | xargs -0 -I XXX json -I -f e.json -e 'this.numbers=XXX'
cat e.json

现在唯一缺少的部分是关于如何使用列表并合并它而不是覆盖值。