Jenkins Pipeline执行Shell命令失败:无法提取JSON变量
解决Jenkins Pipeline中cURL+jq提取JSON变量返回null的问题
我刚看完你的问题,核心问题其实出在Jenkins Pipeline的sh步骤执行机制上——你在Freestyle里是把所有命令放到同一个shell进程里执行的,变量可以互相访问,但迁移到Pipeline时,你把每个命令拆成了单独的sh步骤,每个sh都是独立的子shell,前一个步骤里定义的deployment_info根本传不到后面的步骤,所以jq处理的是空值,自然返回null,最后expr拿null做运算就报错了。
下面给你两种可行的解决方案,按需选择:
方案1:把所有shell命令合并到一个sh块里
这是最直接的解决方式,让所有命令在同一个shell进程中执行,变量就能正常共享了:
pipeline { agent any stages { stage('Fetch & Parse Deployment Data') { steps { sh ''' # 先获取API响应并保存到变量 deployment_info=$(curl -H "Authorization: Basic a123=" "https://api.sample.com/v1") # 用jq提取所需字段 rev_num=$(jq -r .environment[0].revision[0].name <<< "${deployment_info}") env_name=$(jq -r .environment[0].name <<< "${deployment_info}") api_name=$(jq -r .name <<< "${deployment_info}") org_name=$(jq -r .organization <<< "${deployment_info}") # 计算前一个版本号 declare -r num1=1 pre_rev=$(expr "$rev_num" - "$num1") # 输出验证 echo "当前版本号: $rev_num" echo "API名称: $api_name" echo "组织名称: $org_name" echo "环境名称: $env_name" echo "上一个版本号: $pre_rev" ''' } } } }
方案2:把变量提取到Jenkins Pipeline层面(便于后续步骤复用)
如果这些变量需要在Pipeline的其他Groovy步骤中使用(比如后续部署、通知步骤),可以把API响应和提取的字段都捕获为Jenkins环境变量,用Groovy代替shell做运算更稳妥:
pipeline { agent any environment { # 捕获API响应(trim去掉首尾空白符) DEPLOYMENT_DATA = sh( script: 'curl -H "Authorization: Basic a123=" "https://api.sample.com/v1"', returnStdout: true ).trim() # 通过管道用jq提取字段,同样捕获为环境变量 REV_NUM = sh( script: "echo '${DEPLOYMENT_DATA}' | jq -r '.environment[0].revision[0].name // \"0\"'", returnStdout: true ).trim() ENV_NAME = sh( script: "echo '${DEPLOYMENT_DATA}' | jq -r '.environment[0].name'", returnStdout: true ).trim() API_NAME = sh( script: "echo '${DEPLOYMENT_DATA}' | jq -r '.name'", returnStdout: true ).trim() ORG_NAME = sh( script: "echo '${DEPLOYMENT_DATA}' | jq -r '.organization'", returnStdout: true ).trim() } stages { stage('Calculate Previous Revision') { steps { script { // 用Groovy做整数运算,避免shell expr的坑 def preRev = REV_NUM.toInteger() - 1 echo "当前版本号: ${REV_NUM}" echo "API名称: ${API_NAME}" echo "组织名称: ${ORG_NAME}" echo "环境名称: ${ENV_NAME}" echo "上一个版本号: ${preRev}" } } } } }
额外提示
- 我在方案2的jq命令里加了
// "0",这是为了防止JSON字段不存在时返回null,导致后续转整数报错,你可以根据实际情况替换成合适的默认值。 - 如果你的API响应很大,或者需要多次处理,方案1的性能会更好,因为只调用一次cURL;方案2则更灵活,适合跨步骤复用变量。
内容的提问来源于stack exchange,提问作者John Seen
相关产品推荐
相关产品推荐

