Shell 解析 JSON 实战指南:从基础到进阶**
在 Linux/Unix 环境下,Shell 脚本是我们自动化任务、系统管理的重要工具,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,在现代 Web 服务和 API 交互中无处不在,如何在 Shell 脚本中高效地解析 JSON 数据,成为了许多开发者面临的常见挑战,本文将介绍几种在 Shell 中解析 JSON 的方法,从简单的命令行工具到更健壮的脚本编程实践。
为什么 Shell 解析 JSON 有挑战?
Shell 本身并非为处理结构化数据如 JSON 而设计,JSON 的层级嵌套、引号、特殊字符等特性,使得直接使用 Shell 的字符串处理工具(如 grep, awk, sed)变得复杂且容易出错,借助专门的工具或库是更可靠的选择。
方法一:使用 jq—— 强大而流行的 JSON 处理工具
jq 是一个轻量级、灵活的命令行 JSON 处理器,被誉为“Shell 下处理 JSON 的 sed”,它提供了类似 sed 的流式处理能力,可以方便地提取、过滤、转换 JSON 数据。
安装 jq
大多数 Linux 发行版的官方仓库都提供了 jq:
# Debian/Ubuntu sudo apt-get install jq # CentOS/RHEL sudo yum install jq # macOS (使用 Homebrew) brew install jq
jq 基础用法示例
假设我们有如下 JSON 数据,保存在文件 data.json 中:
{
"name": "John Doe",
"age": 30,
"isStudent": false,
"address": {
"street": "123 Main St",
"city": "New York"
},
"hobbies": ["reading", "swimming", "coding"]
}
a. 提取简单值
# 提取 name $ jq '.name' data.json "John Doe" # 提取 age (注意数字会原样输出,不加引号) $ jq '.age' data.json 30 # 提取 isStudent $ jq '.isStudent' data.json false
b. 提取嵌套对象值
# 提取 address.city $ jq '.address.city' data.json "New York"
c. 提取数组元素
# 提取第一个 hobby (索引从 0 开始) $ jq '.hobbies[0]' data.json "reading" # 提取所有 hobbies $ jq '.hobbies[]' data.json "reading" "swimming" "coding"
d. 过滤和转换
# 只包含 name 和 age
$ jq '{name, age}' data.json
{
"name": "John Doe",
"age": 30
}
# 过滤出年龄大于 25 的信息
$ jq 'select(.age > 25)' data.json
{
"name": "John Doe",
"age": 30,
"isStudent": false,
"address": {
"street": "123 Main St",
"city": "New York"
},
"hobbies": ["reading", "swimming", "coding"]
}
e. 在 Shell 脚本中使用 jq
将 jq 的输出赋值给 Shell 变量:
#!/bin/bash name=$(jq -r '.name' data.json) age=$(jq -r '.age' data.json) city=$(jq -r '.address.city' data.json) echo "Name: $name" echo "Age: $age" echo "City: $city" # 处理数组 echo "Hobbies:" jq -r '.hobbies[] | "- " + .' data.json | while read hobby; do echo " $hobby" done
-r 选项表示输出 raw string,即去掉 JSON 字符串的引号,方便直接在 Shell 中使用。
方法二:使用 Python—— 灵活且功能强大
如果系统安装了 Python(通常都有),可以利用 Python 内置的 json 模块来解析 JSON,这种方法更灵活,适合处理复杂的 JSON 逻辑。
示例脚本 parse_json.py:
#!/usr/bin/env python3
import json
import sys
def parse_json_file(file_path):
with open(file_path, 'r') as f:
data = json.load(f)
# 提取简单值
name = data.get('name')
age = data.get('age')
print(f"Name: {name}")
print(f"Age: {age}")
# 提取嵌套值
city = data.get('address', {}).get('city')
print(f"City: {city}")
# 遍历数组
print("Hobbies:")
for hobby in data.get('hobbies', []):
print(f" - {hobby}")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python3 parse_json.py <json_file>")
sys.exit(1)
parse_json_file(sys.argv[1])
在 Shell 中调用:
#!/bin/bash
json_file="data.json"
python_script="parse_json.py"
# 调用 Python 脚本
output=$(python3 "$python_script" "$json_file")
echo "$output"
# 也可以将 Python 脚本的输出捕获到变量中,供后续 Shell 逻辑使用
name=$(python3 -c "import json; data=json.load(open('$json_file')); print(data.get('name'))")
echo "Name from Python one-liner: $name"
方法三:使用其他工具(如 python -m json.tool 格式化)
如果只是需要查看或简单验证 JSON 文件,可以使用 Python 的 JSON 工具:
# 格式化 JSON 文件(美化输出) python -m json.tool data.json # 验证 JSON 文件是否有效 python -m json.tool data.json > /dev/null && echo "Valid JSON" || echo "Invalid JSON"
方法四:使用 jo 和 jc 等辅助工具
jo: 用于从命令行创建 JSON 对象/数组,而不是解析。jc: 可以将多种命令行工具的输出(如df,ps,ipconfig)转换为 JSON 格式,方便后续用jq等工具处理,它也可以尝试解析一些非 JSON 格式为 JSON。
这些工具通常不直接用于解析已有的 JSON 文件,但在构建和转换数据流时很有用。
方法五:不推荐—— 纯 Shell 字符串处理(grep, awk, sed)
对于非常简单、结构固定的 JSON,理论上可以用 grep, awk, sed 等工具通过字符串匹配来提取信息。但这种方法极度脆弱,不推荐在生产环境中使用,因为:
- 难以处理嵌套和复杂结构:JSON 的层级嵌套会让脚本变得异常复杂。
- 容易出错:对引号、转义字符、特殊值(如
null,true,false)处理不当会导致解析失败。 - 维护性差:脚本难以阅读和维护,稍作修改 JSON 结构就可能失效。
示例(仅作演示,非常不推荐):
# 提取 name (假设格式固定) name=$(grep -o '"name": *"[^"]*"' data.json | cut -d'"' -f4) echo "Name: $name"
总结与建议
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
jq |
简单、高效、专为 JSON 设计、功能强大 | 需要额外安装 | 大多数 Shell 脚本中的 JSON 解析需求 |
| Python | 灵活、功能强大、可处理复杂逻辑、跨平台 | 需要安装 Python、脚本相对复杂 | 复杂 JSON 处理、已有 Python 环境 |
| Python 工具 | 快速验证、格式化 JSON | 不适合解析提取特定字段 | JSON 文件查看、简单验证 |
| 纯 Shell | 无需额外安装 | 极其脆弱、难以维护、仅限极简单 JSON | 极其简单、一次性、无维护需求的情况 |
最佳实践建议:
- 优先使用
jq:对于绝大多数 Shell 脚本中的 JSON 解析需求,jq是最佳选择,它专门为此设计,简单易用,性能也足够好。 - 复杂逻辑用 Python:JSON 解析逻辑



还没有评论,来说两句吧...