12

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!

techraf
  • 64,883
  • 27
  • 193
  • 198
Viscosity
  • 311
  • 1
  • 2
  • 14
  • It looks like your question could be shortened to five lines at most. I would suggest using minimal examples that explain the problem and relate to more than your specific case. – techraf Feb 16 '17 at 23:31
  • techraf: I know I can get a little wordy, but in this case, I figured more information was better than less. In the future I will try to see if I can cut this type of text explosion down a bit. – Viscosity Feb 17 '17 at 18:44

3 Answers3

17

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.

techraf
  • 64,883
  • 27
  • 193
  • 198
  • Welp, that is nice to know that stdout_lines utilizes separate lines in list form. However, in my third play/task, if I run it the way you suggest, it fails during the run. The failure it gives is claiming the dict value / arg is undefined, even if I can see during ansible playbook -vvv during the second /play/task that stdout does exist, and I have a variable registered to attempt to catch it. Maybe my shell statement substitution in the third play/task has a problem? – Viscosity Feb 17 '17 at 18:53
0

Can you try as below.

- name: Run command to cat each file and then capture that output.
   shell: cat {{ item.stdout_lines }}
   register: annoying_words
   with_items:
    - "{{ annoying.results }}"
Smily
  • 2,308
  • 2
  • 17
  • 41
0

annoying.stdout_lines is already a list.

From doc of stdout_lines

When stdout is returned, Ansible always provides a list of strings, each containing one item per line from the original output.

To assign the list to another variable do:

    ..
      register: annoying
    - set_fact:
        varName: "{{annoying.stdout_lines}}"
    # print first element on the list
    - debug: msg="{{varName | first}}"
Marinos An
  • 9,481
  • 6
  • 63
  • 96