如何实现Bash函数读取JSON文件,将含数组、对象的所有数据赋值为对应变量
实现Bash读取JSON并映射为原生变量/数组/关联数组的函数
要解决Bash无法原生处理JSON数组和对象的问题,我们可以借助jq工具(轻量且强大的JSON处理器)实现一个递归函数,将JSON结构完整映射为Bash的普通变量、索引数组和关联数组。
函数实现
json_to_bash() { local json_file="$1" # 检查jq是否安装 if ! command -v jq &> /dev/null; then echo "错误:未找到jq工具,请先安装(如:apt install jq / brew install jq)" >&2 return 1 fi # 检查Bash版本(关联数组需要4.0+) if ((BASH_VERSINFO[0] < 4)); then echo "错误:Bash版本需4.0及以上,当前版本为$BASH_VERSION" >&2 return 1 fi # 通过jq生成Bash赋值语句,再用eval执行 eval "$(jq -r ' # 清理键名:替换非法字符为下划线 def sanitize_key($key): $key | gsub("[^a-zA-Z0-9_]"; "_"); # 生成普通变量赋值语句 def emit_var($prefix; $key; $value): "\($prefix)\(sanitize_key($key))=\($value | @sh)"; # 生成索引数组赋值语句 def emit_array($prefix; $key; $array): "\($prefix)\(sanitize_key($key))=(" + ($array[] | @sh) + ")"; # 生成关联数组声明及赋值语句 def emit_assoc_array($prefix; $key; $obj): "declare -A \($prefix)\(sanitize_key($key));" + ($obj | to_entries[] | if .value.type == "object" or .value.type == "array" then empty # 嵌套结构交给递归处理 else "\($prefix)\(sanitize_key($key))[\(sanitize_key(.key))]=\(.value | @sh)" end ); # 递归处理嵌套结构 def process($prefix): . as $in | if type == "object" then to_entries[] | ($prefix + sanitize_key(.key) + "_") as $new_prefix | if .value.type == "object" then emit_assoc_array($prefix; .key; .value) .value | process($new_prefix) elif .value.type == "array" then emit_array($prefix; .key; .value) .value | to_entries[] | ($new_prefix + (.key | tostring) + "_") as $arr_prefix | .value | process($arr_prefix) else emit_var($prefix; .key; .value) end elif type == "array" then to_entries[] | ($prefix + (.key | tostring) + "_") as $arr_prefix | .value | process($arr_prefix) else empty end; # 处理顶层JSON结构 if type == "object" then to_entries[] | if .value.type == "object" then emit_assoc_array(""; .key; .value) .value | process(sanitize_key(.key) + "_") elif .value.type == "array" then emit_array(""; .key; .value) .value | to_entries[] | (sanitize_key(.key) + "_" + (.key | tostring) + "_") as $arr_prefix | .value | process($arr_prefix) else emit_var(""; .key; .value) end elif type == "array" then emit_array(""; "json_array"; .) . | to_entries[] | ("json_array_" + (.key | tostring) + "_") as $arr_prefix | .value | process($arr_prefix) else emit_var(""; "json_var"; .) end ' "$json_file")" }
使用示例
1. 准备测试JSON文件(test.json)
{ "app_name": "MyApp", "version": 1.0, "debug_mode": true, "allowed_users": ["alice", "bob", "charlie"], "database": { "host": "localhost", "port": 5432, "credentials": { "username": "admin", "password": "s3cr3t!@#" } }, "feature_flags": ["auth", {"name": "api", "enabled": false}] }
2. 调用函数
# 加载函数(可以将函数加入~/.bashrc永久生效) source path/to/your/function.sh # 读取JSON文件 json_to_bash test.json
3. 访问映射后的Bash变量
# 普通变量 echo $app_name # 输出: MyApp echo $version # 输出: 1.0 echo $debug_mode # 输出: true # 索引数组 echo "${allowed_users[@]}" # 输出: alice bob charlie echo "${allowed_users[1]}" # 输出: bob # 关联数组 echo "${database["host"]}" # 输出: localhost echo "${database_credentials["password"]}" # 输出: s3cr3t!@# # 数组中的嵌套对象(生成前缀为feature_flags_1_的变量) echo $feature_flags_1_name # 输出: api echo $feature_flags_1_enabled # 输出: false
关键说明
- 键名处理:JSON键中的特殊字符(如
-、.)会被替换为下划线,确保符合Bash变量名规则。 - 类型映射:JSON字符串/数字/布尔/null会转为Bash字符串;JSON数组转为Bash索引数组;JSON对象转为Bash关联数组。
- 嵌套处理:递归解析嵌套的JSON对象和数组,生成带层级前缀的变量/数组,比如
database.credentials转为database_credentials关联数组。 - 安全保障:使用jq的
@sh过滤器自动转义特殊字符,避免命令注入风险,但仍需确保JSON文件来源可信(因为使用了eval)。
内容的提问来源于stack exchange,提问作者Charlweed
相关产品推荐
相关产品推荐

