I have an ansible task where I make use of shell module to run a custom bash script. This bash script expects an optional parameter which could be a multiline string. Example
~/myScript.sh -e "Each \nword \nin \nnew \nline"
This works perfectly fine when I run it in the bash shell. However, I have tried several ways but haven't made it run via the ansible task. The value being a variable itself. The task below -
- name: Sample Task
shell:
cmd: "{{ home_dir }}/myScript.sh -e '{{ string_with_escaped_newlines }}'"
Here, the value of variable string_with_escaped_newlines
is set to Each \nword \nin \nnew \nline
programmatically by other tasks. The output of the task confirms this.
I had put an echo in my shell script to debug & I observe that the echo would print 2 different sequences in the 2 cases(running directly via shell & running via ansible).
Debug output via shell-
Each
word
in
new
line
Debug output via ansible -
Each word in new line
Notice that there is an extra space introduced in the value in place on \n
. I do not understand why this happens and how do I stop this. I have checked/tried shell as well as command modules of ansible.
CodePudding user response:
cmd: "{{ home_dir }}/myScript.sh -e '{{ string_with_escaped_newlines }}'"
is first converted (by Jinja2) to
cmd: "<THE HOME>/myScript.sh -e 'Each \nword \nin \nnew \nline'"
Here \n
is within double quotes and in YAML double quoted \n
s are NEWLINEs (think "\n"
in C or JSON).
For your case you can just write:
cmd: {{ home_dir }}/myScript.sh -e '{{ string_with_escaped_newlines }}'
Or to be more safe:
cmd: |
{{ home_dir }}/myScript.sh -e '{{ string_with_escaped_newlines }}'
YAML syntax is quite "confusing". You can take a look at Ansible's own YAML intro.
CodePudding user response:
Have you tried \r\n
instead of \n
It helped me elsewhere in ansible
CodePudding user response:
Given the scriptshell> cat ~/myScript.sh
#!/usr/bin/sh
echo ${1}
shell> ~/myScript.sh "Each \nword \nin \nnew \nline"
Each
word
in
new
line
Q: "Newline '\n' is replaced by space ' ' in Ansible shell module."
A: It depends on how you quote and escape the string. The simplest option is single-quoted style because only '
need to be escaped
string_with_escaped_newlines1: 'Each \nword \nin \nnew \nline'
You have to escape \n
in double-quoted style
string_with_escaped_newlines2: "Each \\nword \\nin \\nnew \\nline"
Both variables expand to the same string
- debug:
var: string_with_escaped_newlines1
- debug:
var: string_with_escaped_newlines2
gives
string_with_escaped_newlines1: Each \nword \nin \nnew \nline
string_with_escaped_newlines2: Each \nword \nin \nnew \nline
Then, the quotation in the command is not significant. All options below give the same result
- command: ~/myScript.sh "{{ string_with_escaped_newlines1 }}"
- command: ~/myScript.sh '{{ string_with_escaped_newlines1 }}'
- command: ~/myScript.sh "{{ string_with_escaped_newlines2 }}"
- command: ~/myScript.sh '{{ string_with_escaped_newlines2 }}'
Example of a complete playbook for testing
- hosts: localhost
vars:
string_with_escaped_newlines1: 'Each \nword \nin \nnew \nline'
string_with_escaped_newlines2: "Each \\nword \\nin \\nnew \\nline"
tasks:
- command: ~/myScript.sh "{{ string_with_escaped_newlines1 }}"
register: out
- debug:
var: out.stdout_lines
- command: ~/myScript.sh '{{ string_with_escaped_newlines1 }}'
register: out
- debug:
var: out.stdout_lines
- command: ~/myScript.sh "{{ string_with_escaped_newlines2 }}"
register: out
- debug:
var: out.stdout_lines
- command: ~/myScript.sh '{{ string_with_escaped_newlines2 }}'
register: out
- debug:
var: out.stdout_lines
gives (abridged) four times the same result
TASK [debug] *********************************************************
ok: [localhost] =>
out.stdout_lines:
- 'Each '
- 'word '
- 'in '
- 'new '
- line
Notes:
Using shell instead of command gives the same results.
The best practice is using the module command unless the ansible.builtin.shell module is explicitly required.