如何将 "key: value" 序列转换为 JSON?

How can I convert a "key: value" sequence into JSON?

hokay,我正在尝试编写一个脚本,从 yum - repolist all 中获取信息并将其放入漂亮的 JSON 中,供我在一些数据收集中使用。现在我有我的输出从 yum 命令看起来像这样。

我现在的代码只有 yum repolist 命令。

#!/bin/bash -x yum -v repolist all | grep -B2 -A6 "enabled" | sed 's/[[:space:]]//g' , 's/--//g' , 's/name=name=/name=/g'

该命令的输出如下所示:

Repo-id: wazuh_repo
Repo-name: Wazuhrepository
Repo-status: enabled
Repo-revision: 1536348945
Repo-updated: FriSep712:35:512018
Repo-pkgs: 73
Repo-size: 920M
Repo-baseurl: https://packages.wazuh.com/3.x/yum/
Repo-expire: 21,600second(s)(last:WedOct3108:59:002018)

大约有 8 个条目,标题总是相同的...有人可以像我五岁一样解释如何将其转换为 json,我已经阅读了 jq 手册页,我已经阅读哈希的。似乎没有任何意义。我知道我需要有一个 "key"/"value" 如何指定这些?

我只想获取输出并使它看起来漂亮 JSON,这是我正在编写的更大脚本的一部分,以帮助掌握我们在工作中使用的存储库。不过,我完全没有得到 JSON。

编辑:我宁愿不使用包装函数和do/learn正确的方法

所以,首先,没有yum的人可以测试一下,让我们做一个包装函数:

write_output() { cat <<EOF
Repo-id: wazuh_repo
Repo-name: Wazuhrepository
Repo-status: enabled
Repo-revision: 1536348945
Repo-updated: FriSep712:35:512018
Repo-pkgs: 73
Repo-size: 920M
Repo-baseurl: https://packages.wazuh.com/3.x/yum/
Repo-expire: 21,600second(s)(last:WedOct3108:59:002018)
EOF
}

值得注意的是,您所有的键都在字符串 : 之前,而值在它们之后——所以我们要逐行读取,根据冒号-space 序列拆分,把前面的当作键,把后面的当作值。


鉴于:

jq -Rn '[inputs | split(": ")] | reduce .[] as $kv ({}; .[$kv[0]] = $kv[1])' < <(write_output)

...正确发出:

{
  "Repo-id": "wazuh_repo",
  "Repo-name": "Wazuhrepository",
  "Repo-status": "enabled",
  "Repo-revision": "1536348945",
  "Repo-updated": "FriSep712:35:512018",
  "Repo-pkgs": "73",
  "Repo-size": "920M",
  "Repo-baseurl": "https://packages.wazuh.com/3.x/yum/",
  "Repo-expire": "21,600second(s)(last:WedOct3108:59:002018)"
}

...那么,它是如何工作的?

  • jq -R开启原始输入模式;输入被解析为原始字符串序列,而不是 JSON 文档序列。
  • jq -nnull 视为唯一的直接输入,因此可以在脚本中需要的地方使用 inputinputs 原语。
  • [ inputs ] 读取所有输入行,并将它们放入一个数组中。
  • [ inputs | split(": ")] 将其从字符串数组更改为列表数组——在 ": " 序列之前和之后都有内容。
  • reduce .[] as $kv ( {}; ... ) 启动一个 reducer,初始值为 {},然后提供 .[] 求得的每个值(也就是说,您列表中的每个项目)作为 $kv 变量进入该减速器(... 代码),每次替换 . 值。

为了 运行 这个用你的 yum 命令作为真正的输入,改变 < <(write_output)< <(yum -v repolist all | grep -B2 -A6 "enabled" | sed 's/[[:space:]]//g' , 's/--//g' , 's/name=name=/name=/g')

这里是@CharlesDuffy 答案的一个稍微更稳健的变体。由于后者提供了很好的解释性注释,这里不再给出进一步的解释。

jq -nR '
  [inputs | index(": ") as $ix | {(.[:$ix]): .[$ix+2:]}]
  | add'

这避免了在 "value" 包含“:”的情况下使用 split。然而,最好不要假设 space 跟在第一个相关的“:”之后。

另请注意,这里使用 add 而不是 reduce,只是为了简洁。

对于这类问题,我更愿意使用正则表达式来匹配键和值。否则,我会采用类似于 Charles 的方法。

$ ... | jq -Rn 'reduce (inputs | capture("(?<k>[^:]+):\s*(?<v>.+)")) as {$k, $v} ({}; .[$k] = $v)'