Home > Software engineering >  Newline('\n') is replaced by space(' ') in ansible shell module
Newline('\n') is replaced by space(' ') in ansible shell module

Time:08-17

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 \ns 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 script
shell> 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:

  • Related