How to do multiline shell script in Ansible

ShellAnsible

Shell Problem Overview


right now I am using a shell script in ansible that would be much more readable if it was on multiple lines

- name: iterate user groups
  shell: groupmod -o -g {{ item['guid'] }} {{ item['username'] }} ....more stuff to do
  with_items: "{{ users }}"

Just not sure how to allow multiline script in Ansible shell module

Shell Solutions


Solution 1 - Shell

Ansible uses YAML syntax in its playbooks. YAML has a number of block operators:

  • The > is a folding block operator. That is, it joins multiple lines together by spaces. The following syntax:

      key: >
        This text
        has multiple
        lines
    

    Would assign the value This text has multiple lines\n to key.

  • The | character is a literal block operator. This is probably what you want for multi-line shell scripts. The following syntax:

      key: |
        This text
        has multiple
        lines
    

    Would assign the value This text\nhas multiple\nlines\n to key.

You can use this for multiline shell scripts like this:

- name: iterate user groups
  shell: |
    groupmod -o -g {{ item['guid'] }} {{ item['username'] }} 
    do_some_stuff_here
    and_some_other_stuff
  with_items: "{{ users }}"

There is one caveat: Ansible does some janky manipulation of arguments to the shell command, so while the above will generally work as expected, the following won't:

- shell: |
    cat <<EOF
    This is a test.
    EOF

Ansible will actually render that text with leading spaces, which means the shell will never find the string EOF at the beginning of a line. You can avoid Ansible's unhelpful heuristics by using the cmd parameter like this:

- shell:
    cmd: |
      cat <<EOF
      This is a test.
      EOF

Solution 2 - Shell

Tried with ansible 2.0.0.2:

---
- hosts: all
  tasks:
    - name: multiline shell command
      shell: >
        ls --color
        /home
      register: stdout

    - name: debug output
      debug: msg={{ stdout }}

The shell command is collapsed into a single line, as in ls --color /home

Reference (visited in 2021): https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html ==> search form "multiple lines" in the page.

Solution 3 - Shell

Adding a space before the EOF delimiter allows to avoid cmd:

- shell: |
    cat <<' EOF'
    This is a test.
    EOF

Solution 4 - Shell

I prefer this syntax as it allows to set configuration parameters for the shell:

---
- name: an example
  shell:
    cmd: |
      docker build -t current_dir .
      echo "Hello World"
      date

    chdir: /home/vagrant/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSubtubesView Question on Stackoverflow
Solution 1 - ShelllarsksView Answer on Stackoverflow
Solution 2 - ShellMarcello RomaniView Answer on Stackoverflow
Solution 3 - ShellId2ndRView Answer on Stackoverflow
Solution 4 - ShellalfredocamberaView Answer on Stackoverflow