You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 15:57:55