如何在Shell中用JQ遍历嵌套JSON数组并修改指定字段值?
问题说明
需要将JSON中所有title和message字段的值通过trans工具翻译成目标语言,尝试通过遍历数组索引获取字段并替换,但最终所有title和message都变成同一个值,需修正Shell代码。
原始JSON数据:
{ "content": { "macOS": { "releases": [ { "version": "3.21", "updateItems": [ { "id": 1, "title": "Automatic detection for inactivity is here", "message": "We've finally added a feature long requested - Orby now detects when you've been inactive on your computer. You can modify the maximum allowable inactive time through settings, or just turn it off if you don't need it", "image": "https://static.image.png" }, { "id": 2, "title": "In case you missed it... We have an iOS app 📱 🙌", "message": "It's far from perfect, but it's come a long way since we first pushed out version 1.0. We don't that many users on it so far, but I'm hoping that it's useful. Please send any feedback and feature requests my way", "image": "https://static.image.png" } ] } ] }, "iOS": { "releases": [ { "version": "1.31", "updateItems": [ { "image": "https://static.image.png", "id": 1, "link": "orbit://com.orbit:/settings", "message": "Strict mode offers a fantastic new way to keep your focus and get more done. To enable it, go to settings and toggle it on. Now when you want to run a timer, put your device face down on a surface. The timer will stop if you pick it up.", "title": "Strict mode is here 🙌 ⚠️ ⚠️ ⚠️" } ] } ] } } }
原Shell代码存在的问题:
- 索引参数解析错误:直接将
--arg传递的变量插入jq表达式字符串,导致jq无法正确识别索引,所有替换指向同一位置 - 文本引号未处理:用
jq获取字段时未加-r,保留了双引号,传给trans时被错误分割,翻译结果异常 - 更新逻辑缺陷:每次循环通过
echo传递JSON易丢失格式,且重复赋值未正确保留之前的修改 - 未覆盖iOS部分:仅处理macOS的翻译,未涉及iOS的
releases数组
修正后的Shell代码
#!/bin/bash # 获取原始英文JSON curl "${URL}" > englishContent.json LANGUAGES=( # "en" # "de" # "fr" # "es" "it" # "ja" # "ko" # "nl" # "pt-BR" # "ru" # "zh-Hans" ) # 封装翻译函数,处理带空格的文本 translate_text() { local text="$1" local lang="$2" trans -brief -no-warn :"$lang" "$text" | xargs } for language in "${LANGUAGES[@]}"; do # 初始化结果JSON,添加语言标识 result=$(jq --arg lang "$language" '{ "language": $lang, "response": . }' englishContent.json) # 处理macOS平台的updateItems macOS_releases_count=$(jq -r '.response.content.macOS.releases | length' <<< "$result") for ((release_idx=0; release_idx<macOS_releases_count; release_idx++)); do items_count=$(jq -r ".response.content.macOS.releases[$release_idx].updateItems | length" <<< "$result") for ((item_idx=0; item_idx<items_count; item_idx++)); do # 获取不带引号的原始文本 title=$(jq -r ".response.content.macOS.releases[$release_idx].updateItems[$item_idx].title" <<< "$result") translated_title=$(translate_text "$title" "$language") message=$(jq -r ".response.content.macOS.releases[$release_idx].updateItems[$item_idx].message" <<< "$result") translated_message=$(translate_text "$message" "$language") # 单次jq调用完成字段替换,正确解析索引 result=$(jq --arg ridx "$release_idx" --arg iidx "$item_idx" \ --arg new_title "$translated_title" --arg new_msg "$translated_message" \ '.response.content.macOS.releases[$ridx|tonumber].updateItems[$iidx|tonumber] |= (.title = $new_title | .message = $new_msg)' <<< "$result") done done # 处理iOS平台的updateItems iOS_releases_count=$(jq -r '.response.content.iOS.releases | length' <<< "$result") for ((release_idx=0; release_idx<iOS_releases_count; release_idx++)); do items_count=$(jq -r ".response.content.iOS.releases[$release_idx].updateItems | length" <<< "$result") for ((item_idx=0; item_idx<items_count; item_idx++)); do title=$(jq -r ".response.content.iOS.releases[$release_idx].updateItems[$item_idx].title" <<< "$result") translated_title=$(translate_text "$title" "$language") message=$(jq -r ".response.content.iOS.releases[$release_idx].updateItems[$item_idx].message" <<< "$result") translated_message=$(translate_text "$message" "$language") result=$(jq --arg ridx "$release_idx" --arg iidx "$item_idx" \ --arg new_title "$translated_title" --arg new_msg "$translated_message" \ '.response.content.iOS.releases[$ridx|tonumber].updateItems[$iidx|tonumber] |= (.title = $new_title | .message = $new_msg)' <<< "$result") done done # 格式化输出结果,也可保存到文件 echo "$result" | jq '.' done
关键修正点
- 索引正确解析:用
$ridx|tonumber将字符串索引转为数字,让jq准确定位数组元素 - 文本引号处理:使用
jq -r获取无引号的原始文本,避免干扰trans工具的参数解析 - 批量字段更新:单次jq调用同时更新
title和message,减少重复操作 - 全平台覆盖:新增iOS平台的翻译逻辑,确保所有字段被处理
- 代码复用:将翻译逻辑封装为函数,提升可读性和复用性
内容的提问来源于stack exchange,提问作者Joey Slomowitz
相关产品推荐
相关产品推荐

