Jenkins:管道 sh 错误替换错误
Jenkins: Pipeline sh bad substitution error
我的管道中的一个步骤将 .tar 上传到人工服务器。我在传入 env.BUILD_NUMBER 时遇到错误替换错误,但是当数字被硬编码时,相同的命令仍然有效。该脚本是通过 jenkins 在 groovy 中编写的,在 jenkins 工作区中是 运行。
sh 'curl -v --user user:password --data-binary ${buildDir}package${env.BUILD_NUMBER}.tar -X PUT "http://artifactory.mydomain.com/artifactory/release-packages/package${env.BUILD_NUMBER}.tar"'
returns 错误:
[Pipeline] sh
[Package_Deploy_Pipeline] Running shell script
/var/lib/jenkins/workspace/Package_Deploy_Pipeline@tmp/durable-4c8b7958/script.sh: 2:
/var/lib/jenkins/workspace/Package_Deploy_Pipeline@tmp/durable-4c8b7958/script.sh: Bad substitution
[Pipeline] } //node
[Pipeline] Allocate node : End
[Pipeline] End of Pipeline
ERROR: script returned exit code 2
如果在内部版本号中进行硬编码并换出 ${env.BUILD_NUMBER}
我没有收到任何错误并且代码运行成功。
sh 'curl -v --user user:password --data-binary ${buildDir}package113.tar -X PUT "http://artifactory.mydomain.com/artifactory/release-packages/package113.tar"'
我在同一个脚本的其他 sh 命令中使用 ${env.BUILD_NUMBER} 并且在任何其他地方都没有问题。
原来是语法问题。将命令包装在 '
中会导致传递 ${env.BUILD_NUMBER
而不是其值。我将整个命令包装在 "
s 中并转义了嵌套。现在工作正常。
sh "curl -v --user user:password --data-binary ${buildDir}package${env.BUILD_NUMBER}.tar -X PUT \"http://artifactory.mydomain.com/artifactory/release-packages/package${env.BUILD_NUMBER}.tar\""
通常最常见的问题是:
Bad substitution
错误是使用 sh
而不是 bash
。
特别是在使用 Jenkins 时,如果您使用 Execute shell,请确保您的 Command 以 shebang,例如#!/bin/bash -xe
或 #!/usr/bin/env bash
.
实际上,您似乎误解了 env
变量。在您的 sh
块中,您应该直接访问 ${BUILD_NUMBER}
。
Reason/Explanation: env
代表脚本里面的环境。这个环境是 used/available 直接对任何被执行的东西,例如shell 个脚本。
另请注意不要向env.*
写入任何内容,而是使用withEnv{}
块。
我可以肯定地告诉你,这都是关于 sh shell 和 bash shell 的。我通过指定 #!/bin/bash -xe
解决了这个问题,如下所示:
node {
stage("Preparing"){
sh'''#!/bin/bash -xe
colls=( col1 col2 col3 )
for eachCol in ${colls[@]}
do
echo $eachCol
done
'''
}
}
我在 jar 文件的工件中显示 {env.MAJOR_VERSION}
时遇到问题。通过在 Jenkinsfile 中保留环境步骤来显示我的方法。
pipeline {
agent any
environment {
MAJOR_VERSION = 1
}
stages {
stage('build') {
steps {
sh 'ant -f build.xml -v'
}
}
}
post {
always{
archiveArtifacts artifacts: 'dist/*.jar', fingerprint: true
}
}
}
我解决了问题,然后它没有在我的 Jenkins 构建输出中显示错误替换。所以环境步骤在 Jenkinsfile 中扮演更重要的角色。
为了 将 groovy 参数传递到 Jenkins 管道中的 bash 脚本(有时会导致错误的替换)你有 2 个选项:
The triple double quotes way [ " " " ]
OR
the triple single quotes way [ ' ' ' ]
- 在三重双引号中 你可以使用
${someVariable}
从 groovy 渲染普通参数,如果它是环境变量 ${env.someVariable}
,如果它是参数注入你的工作${params.someVariable}
例子:
def YOUR_APPLICATION_PATH= "${WORKSPACE}/myApp/"
sh """#!/bin/bash
cd ${YOUR_APPLICATION_PATH}
npm install
"""
- 在三重单引号中事情变得有点棘手,你可以将参数传递给环境参数并由[=16使用它=] 或使用
''' + someVaraiable + '''
连接groovy参数
例子:
def YOUR_APPLICATION_PATH= "${WORKSPACE}/myApp/"
sh '''#!/bin/bash
cd ''' + YOUR_APPLICATION_PATH + '''
npm install
'''
或
pipeline{
agent { node { label "test" } }
environment {
YOUR_APPLICATION_PATH = "${WORKSPACE}/myapp/"
}
continue...
continue...
continue...
sh '''#!/bin/bash
cd "${YOUR_APPLICATION_PATH}"
npm install
'''
//OR
sh '''#!/bin/bash
cd "${env.YOUR_APPLICATION_PATH}"
npm install
'''
我在为 Amazon S3 应用程序上传 Jenkins 管道工作时遇到了同样的问题。
我的脚本是这样的:
pipeline {
agent any
parameters {
string(name: 'Bucket', defaultValue: 's3-pipeline-test', description: 'The name of the Amazon S3 Bucket')
string(name: 'Prefix', defaultValue: 'my-website', description: 'Application directory in the Amazon S3 Bucket')
string(name: 'Build', defaultValue: 'public/', description: 'Build directory for the application')
}
stages {
stage('Build') {
steps {
echo 'Running build phase'
sh 'npm install' // Install packages
sh 'npm run build' // Build project
sh 'ls' // List project files
}
}
stage('Deploy') {
steps {
echo 'Running deploy phase'
withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWSCredentials', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
sh 'aws s3 ls' // List AWS S3 buckets
sh 'aws s3 sync "${params.Build}" s3://"${params.Bucket}/${params.Prefix}" --delete' // Sync project files with AWS S3 Bucket project path
}
}
}
}
post {
success {
echo 'Deployment to Amazon S3 suceeded'
}
failure {
echo 'Deployment to Amazon S3 failed'
}
}
}
这是我修复它的方法:
看到是变量的插值调用,只好把这行脚本中的单引号(' ')换掉:
sh 'aws s3 sync "${params.Build}" s3://"${params.Bucket}/${params.Prefix}" --delete' // Sync project files with AWS S3 Bucket project path
转双引号(" "):
sh "aws s3 sync ${params.Build} s3://${params.Bucket}/${params.Prefix} --delete" // Sync project files with AWS S3 Bucket project path
所以我的脚本之后看起来像这样:
pipeline {
agent any
parameters {
string(name: 'Bucket', defaultValue: 's3-pipeline-test', description: 'The name of the Amazon S3 Bucket')
string(name: 'Prefix', defaultValue: 'my-website', description: 'Application directory in the Amazon S3 Bucket')
string(name: 'Build', defaultValue: 'public/', description: 'Build directory for the application')
}
stages {
stage('Build') {
steps {
echo 'Running build phase'
sh 'npm install' // Install packages
sh 'npm run build' // Build project
sh 'ls' // List project files
}
}
stage('Deploy') {
steps {
echo 'Running deploy phase'
withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWSCredentials', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
sh 'aws s3 ls' // List AWS S3 buckets
sh "aws s3 sync ${params.Build} s3://${params.Bucket}/${params.Prefix} --delete" // Sync project files with AWS S3 Bucket project path
}
}
}
}
post {
success {
echo 'Deployment to Amazon S3 suceeded'
}
failure {
echo 'Deployment to Amazon S3 failed'
}
}
}
就这些了
希望对您有所帮助
Jenkins 脚本在“sh”中失败 command-line 例如:
sh 'npm run build' <-- Fails referring to package.json
需要改为:
sh 'npm run ng build....'
... package.json.
找不到 ng $PATH
我的管道中的一个步骤将 .tar 上传到人工服务器。我在传入 env.BUILD_NUMBER 时遇到错误替换错误,但是当数字被硬编码时,相同的命令仍然有效。该脚本是通过 jenkins 在 groovy 中编写的,在 jenkins 工作区中是 运行。
sh 'curl -v --user user:password --data-binary ${buildDir}package${env.BUILD_NUMBER}.tar -X PUT "http://artifactory.mydomain.com/artifactory/release-packages/package${env.BUILD_NUMBER}.tar"'
returns 错误:
[Pipeline] sh
[Package_Deploy_Pipeline] Running shell script
/var/lib/jenkins/workspace/Package_Deploy_Pipeline@tmp/durable-4c8b7958/script.sh: 2:
/var/lib/jenkins/workspace/Package_Deploy_Pipeline@tmp/durable-4c8b7958/script.sh: Bad substitution
[Pipeline] } //node
[Pipeline] Allocate node : End
[Pipeline] End of Pipeline
ERROR: script returned exit code 2
如果在内部版本号中进行硬编码并换出 ${env.BUILD_NUMBER}
我没有收到任何错误并且代码运行成功。
sh 'curl -v --user user:password --data-binary ${buildDir}package113.tar -X PUT "http://artifactory.mydomain.com/artifactory/release-packages/package113.tar"'
我在同一个脚本的其他 sh 命令中使用 ${env.BUILD_NUMBER} 并且在任何其他地方都没有问题。
原来是语法问题。将命令包装在 '
中会导致传递 ${env.BUILD_NUMBER
而不是其值。我将整个命令包装在 "
s 中并转义了嵌套。现在工作正常。
sh "curl -v --user user:password --data-binary ${buildDir}package${env.BUILD_NUMBER}.tar -X PUT \"http://artifactory.mydomain.com/artifactory/release-packages/package${env.BUILD_NUMBER}.tar\""
通常最常见的问题是:
Bad substitution
错误是使用 sh
而不是 bash
。
特别是在使用 Jenkins 时,如果您使用 Execute shell,请确保您的 Command 以 shebang,例如#!/bin/bash -xe
或 #!/usr/bin/env bash
.
实际上,您似乎误解了 env
变量。在您的 sh
块中,您应该直接访问 ${BUILD_NUMBER}
。
Reason/Explanation: env
代表脚本里面的环境。这个环境是 used/available 直接对任何被执行的东西,例如shell 个脚本。
另请注意不要向env.*
写入任何内容,而是使用withEnv{}
块。
我可以肯定地告诉你,这都是关于 sh shell 和 bash shell 的。我通过指定 #!/bin/bash -xe
解决了这个问题,如下所示:
node {
stage("Preparing"){
sh'''#!/bin/bash -xe
colls=( col1 col2 col3 )
for eachCol in ${colls[@]}
do
echo $eachCol
done
'''
}
}
我在 jar 文件的工件中显示 {env.MAJOR_VERSION}
时遇到问题。通过在 Jenkinsfile 中保留环境步骤来显示我的方法。
pipeline {
agent any
environment {
MAJOR_VERSION = 1
}
stages {
stage('build') {
steps {
sh 'ant -f build.xml -v'
}
}
}
post {
always{
archiveArtifacts artifacts: 'dist/*.jar', fingerprint: true
}
}
}
我解决了问题,然后它没有在我的 Jenkins 构建输出中显示错误替换。所以环境步骤在 Jenkinsfile 中扮演更重要的角色。
为了 将 groovy 参数传递到 Jenkins 管道中的 bash 脚本(有时会导致错误的替换)你有 2 个选项:
The triple double quotes way [ " " " ] OR the triple single quotes way [ ' ' ' ]
- 在三重双引号中 你可以使用
${someVariable}
从 groovy 渲染普通参数,如果它是环境变量${env.someVariable}
,如果它是参数注入你的工作${params.someVariable}
例子:
def YOUR_APPLICATION_PATH= "${WORKSPACE}/myApp/"
sh """#!/bin/bash
cd ${YOUR_APPLICATION_PATH}
npm install
"""
- 在三重单引号中事情变得有点棘手,你可以将参数传递给环境参数并由[=16使用它=] 或使用
''' + someVaraiable + '''
连接groovy参数
例子:
def YOUR_APPLICATION_PATH= "${WORKSPACE}/myApp/"
sh '''#!/bin/bash
cd ''' + YOUR_APPLICATION_PATH + '''
npm install
'''
或
pipeline{
agent { node { label "test" } }
environment {
YOUR_APPLICATION_PATH = "${WORKSPACE}/myapp/"
}
continue...
continue...
continue...
sh '''#!/bin/bash
cd "${YOUR_APPLICATION_PATH}"
npm install
'''
//OR
sh '''#!/bin/bash
cd "${env.YOUR_APPLICATION_PATH}"
npm install
'''
我在为 Amazon S3 应用程序上传 Jenkins 管道工作时遇到了同样的问题。
我的脚本是这样的:
pipeline {
agent any
parameters {
string(name: 'Bucket', defaultValue: 's3-pipeline-test', description: 'The name of the Amazon S3 Bucket')
string(name: 'Prefix', defaultValue: 'my-website', description: 'Application directory in the Amazon S3 Bucket')
string(name: 'Build', defaultValue: 'public/', description: 'Build directory for the application')
}
stages {
stage('Build') {
steps {
echo 'Running build phase'
sh 'npm install' // Install packages
sh 'npm run build' // Build project
sh 'ls' // List project files
}
}
stage('Deploy') {
steps {
echo 'Running deploy phase'
withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWSCredentials', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
sh 'aws s3 ls' // List AWS S3 buckets
sh 'aws s3 sync "${params.Build}" s3://"${params.Bucket}/${params.Prefix}" --delete' // Sync project files with AWS S3 Bucket project path
}
}
}
}
post {
success {
echo 'Deployment to Amazon S3 suceeded'
}
failure {
echo 'Deployment to Amazon S3 failed'
}
}
}
这是我修复它的方法:
看到是变量的插值调用,只好把这行脚本中的单引号(' ')换掉:
sh 'aws s3 sync "${params.Build}" s3://"${params.Bucket}/${params.Prefix}" --delete' // Sync project files with AWS S3 Bucket project path
转双引号(" "):
sh "aws s3 sync ${params.Build} s3://${params.Bucket}/${params.Prefix} --delete" // Sync project files with AWS S3 Bucket project path
所以我的脚本之后看起来像这样:
pipeline {
agent any
parameters {
string(name: 'Bucket', defaultValue: 's3-pipeline-test', description: 'The name of the Amazon S3 Bucket')
string(name: 'Prefix', defaultValue: 'my-website', description: 'Application directory in the Amazon S3 Bucket')
string(name: 'Build', defaultValue: 'public/', description: 'Build directory for the application')
}
stages {
stage('Build') {
steps {
echo 'Running build phase'
sh 'npm install' // Install packages
sh 'npm run build' // Build project
sh 'ls' // List project files
}
}
stage('Deploy') {
steps {
echo 'Running deploy phase'
withCredentials([[$class: 'AmazonWebServicesCredentialsBinding', accessKeyVariable: 'AWS_ACCESS_KEY_ID', credentialsId: 'AWSCredentials', secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) {
sh 'aws s3 ls' // List AWS S3 buckets
sh "aws s3 sync ${params.Build} s3://${params.Bucket}/${params.Prefix} --delete" // Sync project files with AWS S3 Bucket project path
}
}
}
}
post {
success {
echo 'Deployment to Amazon S3 suceeded'
}
failure {
echo 'Deployment to Amazon S3 failed'
}
}
}
就这些了
希望对您有所帮助
Jenkins 脚本在“sh”中失败 command-line 例如:
sh 'npm run build' <-- Fails referring to package.json
需要改为:
sh 'npm run ng build....'
... package.json.
找不到 ng $PATH