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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:25:30