使用bq中管道分隔的键和值使用jq创建JSON

我试图从bash中的字符串创建一个json对象。字符串如下。

CONTAINER|CPU%|MEMUSAGE/LIMIT|MEM%|NETI/O|BLOCKI/O|PIDS

nginx_container|0.02%|25.09MiB/15.26GiB|0.16%|0B/0B|22.09MB/4.096kB|0

输出来自docker stats命令,我的最终目标是将自定义指标发布到AWS CloudWatch。我想将此字符串格式化为json。

{

"CONTAINER":"nginx_container",

"CPU%":"0.02%",

....

}

我以前使用过jq命令,似乎在这种情况下应该可以正常工作,但是我还没有想出一个好的解决方案。除了使用sed或awk对变量名进行硬编码和索引编制之外。然后从头开始创建一个json。任何建议,将不胜感激。谢谢。

回答:

先决条件

对于以下所有内容,假定您的内容位于名为的shell变量中s

s='CONTAINER|CPU%|MEMUSAGE/LIMIT|MEM%|NETI/O|BLOCKI/O|PIDS

nginx_container|0.02%|25.09MiB/15.26GiB|0.16%|0B/0B|22.09MB/4.096kB|0'

什么(现代jq)

# thanks to @JeffMercado and @chepner for refinements, see comments

jq -Rn '

( input | split("|") ) as $keys |

( inputs | split("|") ) as $vals |

[[$keys, $vals] | transpose[] | {key:.[0],value:.[1]}] | from_entries

' <<<"$s"

如何(现代jq)

这需要非常新的(可能是1.5?)jq才能工作,并且是一堆密集的代码。分解:

  • using -n阻止jq自己读取stdin,而让inputand 可以读取整个输入流inputs-前者读取一行,而后者读取所有其余行。(-R,对于原始输入,导致读取文本行而不是JSON对象)。
  • 使用[$keys, $vals] | transpose[],我们生成了[key, value]对(以Python的术语来说,将两个列表压缩在一起)。
  • 使用{key:.[0],value:.[1]},我们将每一[key, value]对变成以下形式的对象{"key": key, "value": value}
  • 使用from_entries,我们将这些对组合为包含这些键和值的对象。


什么(Shell assisted)

jq将比上述版本更旧,并且在本地jq解决方案可能更难以解决的情况下是一种易于采用的方法:

{

IFS='|' read -r -a keys # read first line into an array of strings

## read each subsequent line into an array named "values"

while IFS='|' read -r -a values; do

# setup: positional arguments to pass in literal variables, query with code

jq_args=( )

jq_query='.'

# copy values into the arguments, reference them from the generated code

for idx in "${!values[@]}"; do

[[ ${keys[$idx]} ]] || continue # skip values with no corresponding key

jq_args+=( --arg "key$idx" "${keys[$idx]}" )

jq_args+=( --arg "value$idx" "${values[$idx]}" )

jq_query+=" | .[\$key${idx}]=\$value${idx}"

done

# run the generated command

jq "${jq_args[@]}" "$jq_query" <<<'{}'

done

} <<<"$s"


如何(Shell assisted)

jq上面调用的命令类似于:

jq --arg key0   'CONTAINER' \

--arg value0 'nginx_container' \

--arg key1 'CPU%' \

--arg value1 '0.0.2%' \

--arg key2 'MEMUSAGE/LIMIT' \

--arg value2 '25.09MiB/15.26GiB' \

'. | .[$key0]=$value0 | .[$key1]=$value1 | .[$key2]=$value2' \

<<<'{}'

…将每个键和值带外传递(这样就将其视为文字字符串而不是解析为JSON),然后分别引用它们。


结果

以上任何一种都会发出:

{

"CONTAINER": "nginx_container",

"CPU%": "0.02%",

"MEMUSAGE/LIMIT": "25.09MiB/15.26GiB",

"MEM%": "0.16%",

"NETI/O": "0B/0B",

"BLOCKI/O": "22.09MB/4.096kB",

"PIDS": "0"

}


为什么

简而言之: 因为可以保证生成有效的JSON作为output

考虑以下示例,该示例将打破更多幼稚的方法:

s='key ending in a backslash\

value "with quotes"'

当然,这些是意外情况,但是jq知道如何处理它们:

{

"key ending in a backslash\\": "value \"with quotes\""

}

…而一个不理解JSON字符串的实现很容易最终发出:

{

"key ending in a backslash\": "value "with quotes""

}

以上是 使用bq中管道分隔的键和值使用jq创建JSON 的全部内容, 来源链接: utcz.com/qa/403755.html

回到顶部