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

Bash脚本中使用jq执行数值运算报错,寻求解决方案

问题分析与解决

报错核心原因

你遇到的Invalid numeric literal错误,根源是变量引用和jq参数传递的问题:

  • 用单引号定义Args变量时,$Port不会被Bash解析替换,导致jq收到的是字符串$Port而非数字1050,无法解析为合法数值。
  • 脚本还存在其他逻辑缺陷,比如循环覆盖JSON内容、键名语法错误、重复查询hosts等,都会导致不符合预期或报错。

修正后的完整脚本

JSFl="/tmp/test.json"
Port=1050

# 初始化空JSON对象(文件不存在或为空时执行)
[[ ! -s "$JSFl" ]] && echo '{}' > "$JSFl"

for Srv in $(cat /tmp/servers); do
  # 单次查询hosts,同时获取IP和主机名,减少IO操作
  read -r IPn NodeNm <<< "$(grep "$Srv" /etc/hosts | awk '{print $1, $2}')"
  
  # 用数组存储jq参数,避免字符串分词导致的参数混乱
  Args=(
    --arg S "$Srv"
    --arg Node "$NodeNm"
    --arg IP "$IPn"
    --argjson P1 "$Port"  # 直接传递数字类型,无需后续转换
  )

  # 使用jq的+=操作合并对象,保留原有内容并新增键值对
  jq "${Args[@]}" '. += {$S: {"Node": $Node, "PubIP": $IP, "Port1": $P1, "Port2": $P1-1, "Port3": $P1+2}}' "$JSFl" > tmp.json && mv -f tmp.json "$JSFl"
done

关键修正说明

  • 参数传递优化:用数组存储jq参数,避免字符串分词错误;用--argjson直接传递数字类型的端口值,省去tonumber转换步骤。
  • JSON合并逻辑:用. += {$S: ...}实现新增键值对,而非每次覆盖整个文件,保证循环能添加多个服务器的数据。
  • hosts查询优化:单次完成grep+awk操作,并用read同时读取IP和主机名,提升执行效率。
  • 空文件处理:提前生成空JSON对象{},避免第一次执行时jq处理空文件的异常。
  • 语法修正:Bash循环关键字为小写for,原脚本的For会被当作未知命令报错;jq中用{$S}动态生成键名,原脚本的"$S"会把字符串$S作为键名,而非变量值。

预期生成结果

执行脚本后,/tmp/test.json会生成符合要求的多字段JSON:

{
  "Comp1": {
    "Node": "C1VM1",
    "PubIP": "1.2.3.4",
    "Port1": 1050,
    "Port2": 1049,
    "Port3": 1052
  },
  "Comp2": {
    "Node": "C2VM1",
    "PubIP": "5.6.7.8",
    "Port1": 1050,
    "Port2": 1049,
    "Port3": 1052
  }
}

内容的提问来源于stack exchange,提问作者DenisZ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:17:23