如何用jq优雅生成基于文件行的嵌套结构JSON数组?
问题描述
我有一个多行文本文件prefixes.txt,内容如下:
row1 row2
我需要针对每行生成包含两个对象的数组,其中第一组后缀为first,第二组为last,结构如下:
[ { "forward": "forward-row1-first", "reverse": "reverse-row1-first" }, { "forward": "forward-row1-last", "reverse": "reverse-row1-last" } ]
最终要把每行对应的上述结构组合成外层数组,每个元素包含reads字段,格式如下:
[ { "reads": [ { "forward": "forward-row1-first", "reverse": "reverse-row1-first" }, { "forward": "forward-row1-last", "reverse": "reverse-row1-last" } ] }, { "reads": [ { "forward": "forward-row2-first", "reverse": "reverse-row2-first" }, { "forward": "forward-row2-last", "reverse": "reverse-row2-last" } ] } ]
我写了一段bash脚本,但输出不符合预期:
create_json () { ROW="$1" for SUFFIX in 1 2; do FORWARD="forward-${ROW}_${SUFFIX}" REVERSE="reverse-${ROW}_${SUFFIX}" jq -n --arg forward "$FORWARD" --arg reverse "$REVERSE" '{forward: $forward, reverse: $reverse}' done | jq -n '.reads |= [inputs]' } DATA=() while read -r line; do DATA+=($(create_json $line)) done < prefixes.txt echo "${DATA[*]}"
这段代码的输出是多个独立的JSON对象拼接在一起,没有外层数组,格式混乱:
{ "reads": [ { "forward": "forward-row1_first", "reverse": "reverse-row1_first" }, { "forward": "forward-row1_last", "reverse": "reverse-row1_last" } ] } { "reads": [ { "forward": "forward-row2_first", "reverse": "reverse-row2_first" }, { "forward": "forward-row2_last", "reverse": "reverse-row2_last" } ] }
请问怎么用jq优雅实现预期的输出格式?
解决方案
完全不需要bash数组循环,用jq单命令就能搞定,效率更高也更简洁:
方式一:两次调用jq(直观易读)
jq -R ' . as $row | [ {forward: "forward-\($row)-first", reverse: "reverse-\($row)-first"}, {forward: "forward-\($row)-last", reverse: "reverse-\($row)-last"} ] | {reads: .} ' prefixes.txt | jq -s .
代码解释:
-R:告诉jq把每行输入当作原始字符串处理,不解析成JSON- 用
$row存储当前行内容,构造包含两个对象的数组,替换对应后缀 - 将数组包裹成
{reads: ...}结构,输出每行对应的JSON对象 - 最后用
jq -s .把所有独立JSON对象合并成外层数组,并自动格式化输出
方式二:单次调用jq(更高效)
如果想避免两次调用jq,可直接用以下写法:
jq -Rs ' split("\n") | map(select(length > 0)) | map( . as $row | {reads: [ {forward: "forward-\($row)-first", reverse: "reverse-\($row)-first"}, {forward: "forward-\($row)-last", reverse: "reverse-\($row)-last"} ]} ) ' prefixes.txt
代码解释:
-Rs:-R读原始字符串,-s把所有输入合并成单个字符串split("\n"):按换行分割成数组,map(select(length > 0))过滤空行- 对每行生成对应的
reads结构,最后直接输出格式化后的外层数组
这两种方式都完全用jq处理JSON结构,避免了bash数组处理JSON时的格式混乱问题,实现优雅且高效。
内容的提问来源于stack exchange,提问作者M.M
相关产品推荐
相关产品推荐

