如何通过Groovy将含空格的Jenkins环境变量传递给Ansible命令
I’ve run into this exact shell parameter splitting gotcha before—spaces in variables from Jenkins can trip you up in unexpected ways! Let’s break down the fix:
The Root Cause
When you define computer_args ="ansible-playbook deploy.yml -e COMPUTER_NAME=${env.COMPUTER_NAME}" in your Jenkinsfile, Groovy first interpolates the variable, resulting in a raw command string like:
ansible-playbook deploy.yml -e COMPUTER_NAME=HELLO WORLD
The Linux shell sees the space and treats WORLD as a separate, standalone parameter. Ansible then mistakes this extra parameter for a playbook file, hence the ERROR! the playbook: WORLD could not be found error.
In your direct shell test, you were implicitly handling the quoting (even if you didn’t realize it)—when you export the variable and run the command with proper quoting around the value, the shell keeps the entire string intact as one parameter.
Solutions
1. Wrap the Variable Assignment in Quotes (Groovy-Safe)
Add an extra layer of quoting around the -e argument’s value to ensure the shell treats it as a single parameter. You have two clean options:
Option A: Escaped Double Quotes
script { env.COMPUTER_NAME = "HELLO WORLD" def computer_args = "ansible-playbook deploy.yml -e \"COMPUTER_NAME=${env.COMPUTER_NAME}\"" sh(computer_args) }
Groovy interpolates the variable and outputs a shell-friendly command:
ansible-playbook deploy.yml -e "COMPUTER_NAME=HELLO WORLD"
Option B: Single Quotes (Avoids Escaping)
script { env.COMPUTER_NAME = "HELLO WORLD" def computer_args = "ansible-playbook deploy.yml -e 'COMPUTER_NAME=${env.COMPUTER_NAME}'" sh(computer_args) }
This generates:
ansible-playbook deploy.yml -e 'COMPUTER_NAME=HELLO WORLD'
2. Use a Multiline Shell Script (Cleaner for Complex Commands)
For better readability, especially with longer or more complex commands, use a multiline string in your sh step. This makes quoting straightforward:
stage('Deploy with Ansible') { steps { script { env.COMPUTER_NAME = "HELLO WORLD" sh """ ansible-playbook deploy.yml -e "COMPUTER_NAME=${env.COMPUTER_NAME}" """ } } }
3. Pass as a Command Array (Most Robust)
If you want to avoid any quoting headaches entirely, pass the command as an array. This ensures each element is treated as a single parameter, eliminating shell splitting entirely:
script { def command = [ 'ansible-playbook', 'deploy.yml', '-e', "COMPUTER_NAME=${env.COMPUTER_NAME}" ] sh(command.join(' ')) }
Why This Works
All these methods guarantee that when the shell executes the command, the entire COMPUTER_NAME=HELLO WORLD string is passed as one complete argument to Ansible’s -e flag. Ansible will then correctly parse the variable value without splitting on spaces.
内容的提问来源于stack exchange,提问作者user2920657

