Search code examples
shellansible

How to do multiline shell script in Ansible


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


Solution

  • 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 }}"
    

    (Update in 2024: the following is no longer true; Ansible is now less janky.)

    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
    

    @JKLaiho points out in a comment that the behavior of > is perhaps unexpected if you include additional indentation in your string. If you write:

    key: >
      this
        is
          a
            test
    

    You will get the value:

    "this\n  is\n    a\n      test\n"