How to store command output into array in Ansible?

Viscosity picture Viscosity · Feb 16, 2017 · Viewed 16k times · Source

Essentially, I want to be able to handle "wildcard filenames" in Linux using ansible. In essence, this means using the ls command with part of a filename followed by an "*" so that it will list ONLY certain files.

However, I cannot store the output properly in a variable as there will likely be more than one filename returned. Thus, I want to be able to store these results no matter how many there might be in an array during one task. I then want to be able to retrieve all of the results from the array in a later task. Furthermore, since I don't know how many files might be returned, I cannot do a task for each filename, and an array makes more sense.

The reason behind this is that there are files in a random storage location that are changed often, but they always have the same first half. It's their second half of their names that are random, and I don't want to have to hard code that into ansible at all.

I'm not certain at all how to properly implement/manipulate an array in ansible, so the following code is an example of what I'm "trying" to accomplish. Obviously it won't function as intended if more than one filename is returned, which is why I was asking for assistance on this topic:

- hosts: <randomservername>
  remote_user: remoteguy
  become: yes
  become_method: sudo
  vars:
    aaaa: b
  tasks:

 - name: Copy over all random file contents from directory on control node to target clients.  This is to show how to manipulate wildcard filenames.
    copy:
      src: /opt/home/remoteguy/copyable-files/testdir/
      dest: /tmp/
      owner: remoteguy
      mode: u=rwx,g=r,o=r
    ignore_errors: yes

  - name: Determine the current filenames and store in variable for later use, obviously for this exercise we know part of the filenames.
    shell: "ls {{item}}"
    changed_when: false
    register: annoying
    with_items: [/tmp/this-name-is-annoying*, /tmp/this-name-is-also*]

  - name: Run command to cat each file and then capture that output.
    shell: cat {{ annoying }}
    register: annoying_words

  - debug: msg=Here is the output of the two files.  {{annoying_words.stdout_lines }}

  - name: Now, remove the wildcard files from each server to clean up.
    file:
      path: '{{ item }}'
      state: absent
    with_items:
    - "{{ annoying.stdout }}"

I understand the YAML format got a little mussed up, but if it's fixed, this "would" run normally, it just won't give me the output I'm looking for. Thus if there were 50 files, I'd want ansible to be able to manipulate them all, and/or be able to delete them all.. etc etc etc.

If anyone here could let me know how to properly utilize an array in the above test code fragment that would be fantastic!

Answer

techraf picture techraf · Feb 17, 2017

Ansible stores the output of shell and command action modules in stdout and stdout_lines variables. The latter contains separate lines of the standard output in a form of a list.

To iterate over the elements, use:

with_items:
  - "{{ annoying.stdout_lines }}"

You should remember that parsing ls output might cause problems in some cases.