using register stdout_lines in with_items loop

22,171 views
Skip to first unread message

Jason Gilfoil

unread,
Feb 22, 2016, 10:19:47 AM2/22/16
to Ansible Project
Hello All,

I'm ultimately attempting to pull a list of files with wildcarded paths and pass the results into the replace module so it can cycle through them all. However, starting with a more simple example, i'm having issues getting the list of files to print properly in even a simple test case.


Pastebin code:

I'm looking for this:

test.yml playbook
 
- hosts: all
  tasks:
    - name: gather list of files
      shell: ls {{ item }}
      register: files
      with_items:
        - /app/psoft/test/*/list.txt
        - /app/psoft/test/*/context.xml
 
    - name: use shell to print list of file paths
      shell: "echo {{ item }}"
      with_items: "{{files.stdout_lines}}"


to print

/app/psoft/test/12.1.2.00/list.txt
/app/psoft/test/12.1.3.00/context.xml

However currently the result is:

TASK [gather list of files] ****************************************************
changed: [net12204] => (item=/app/psoft/test/*/list.txt)
changed: [net12204] => (item=/app/psoft/test/*/context.xml)

TASK [use shell to print list of file paths] ***********************************
[DEPRECATION WARNING]: Skipping task due to undefined attribute, in the future this will be a fatal error.. This feature will
be removed in a future release. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.




Thanks!
Jason

Jason Gilfoil

unread,
Feb 23, 2016, 1:51:36 PM2/23/16
to Ansible Project
So after some testing and reading i'm gonna attempt to answer my own question, and pose another one.

The documentation I cited for iterating the results of a program execution didn't involve the use of with_items in the original program execution. Having multiple results in a register variable doesn't seem to play nice with 'with_items'. 

I decided to work around the issue by having multiple tasks to gather the file names and iterate over each result in the replace module.

As a corollary to that, when using with_items and setting a failed_when condition, you can't seem to use the 'rc' property of the register variable in a task because the rc code only exists if the task fails. I'm thinking there must be a way to say fail_when: the register.rc exists, but haven't figured that part out yet.

Matt Martz

unread,
Feb 23, 2016, 2:04:59 PM2/23/16
to ansible...@googlegroups.com
The "problem" is in how ansible registers results when using with_items.  It nests all of the results inside of a `results` key

Your second task could have been written to use:

    - name: use shell to print list of file paths
      shell: "echo {{ item }}"
      with_items: "{{ files.results|map(attribute='stdout_lines')|list }}"

That would do it for you.  That pulls the `stdout_lines` attribute out into a list of `stdout_lines`, then with_items natively handles the flattening, allowing you to loop over each individual item in the `ls` output.

There is some documentation about using register with a loop, which you can find at http://docs.ansible.com/ansible/playbooks_loops.html#using-register-with-a-loop

--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/82ae7301-06d6-42e9-a4f3-cf017f09ed22%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Matt Martz
@sivel
sivel.net

Adam

unread,
May 29, 2019, 9:12:22 PM5/29/19
to Ansible Project
Matt - 

I don't know how you figured out how to do this (I would love to know), but it should DEFINITELY be in the documentation.  It's not pretty, but it works and it solved my issue.      It's definitely easier than breaking it into multiple tasks or having to populate a list manually.

- name: get list of directories
shell: "egrep '^archive.directory|^outgoing.directory|^incoming.directory' {{conf_dir}}/{{item.1.config}}|cut -d '=' -f2|sort|uniq"
with_subelements:
- "{{loggers}}"
- configs
register: directoriesToBuild

- name: debug directory output
debug:
msg: "{{directoriesToBuild.results|map(attribute='stdout_lines')|list}}"

- name: build found directories
file:
state: directory
path: "{{item}}"
with_items:
- "{{directoriesToBuild.results|map(attribute='stdout_lines')|list}}"

-Adam
To unsubscribe from this group and stop receiving emails from it, send an email to ansible...@googlegroups.com.

To post to this group, send email to ansible...@googlegroups.com.

Adam

unread,
May 29, 2019, 9:27:43 PM5/29/19
to Ansible Project
I was over zealous & too hopeful.. this doesn't actually work for me.  It looks like it treats the whole list of directories as one big directory.  I'm not entirely sure why yet. 

Adam

unread,
May 30, 2019, 9:19:35 AM5/30/19
to Ansible Project
After spending several hours trying different combinations of tasks, filters, combinations of filters, etc, I decided I spent too much time trying to do it all in memory.  Here was my final solution that works:

- name: make sure temp file doesn't exist
file:
state: absent
path: "{{appdataRoot}}/directoriesToBuild.tmp"

- name: get list of directories to build
shell: "egrep '^archive.directory|^outgoing.directory|^incoming.directory' {{conf_dir}}/{{item.1.config}}|cut -d '=' -f2|sort|uniq >> {{appdataRoot}}/directoriesToBuild.tmp"
  with_subelements:
- "{{loggers}}"
- configs

- name: put list of directories into a variable
shell: "cat {{appdataRoot}}/directoriesToBuild.tmp"
register: directoriesToBuild


- name: build found directories
file:
state: directory
path: "{{item}}"
with_items:
    - "{{directoriesToBuild.stdout_lines}}"

David Gorsett

unread,
Dec 22, 2022, 12:51:05 PM12/22/22
to Ansible Project
This page was the starting point of me figuring out how to print the 'results[*].stdout_lines' of a registered return value. So, I thought I ought to share what I found to work, as it's quite short and re-usable with any return value that produces a list. It also provides flexibility to add more fields to the output.

If 'stdout_lines' is the only variable in the select, the resulting array will be all 1 liners, rather than grouped by result. 'item' within each result in the list displays the item name provided when the list was produced.

    - name: Show 'item' & 'stdout_lines' per result
      debug: var=item
      loop: "{{ result | json_query('results[*].{item: item, stdout_lines: stdout_lines}') }}"

    - name: Only show 'stdout_lines' per result
      debug: var=item.stdout_lines
      loop: "{{ result | json_query('results[*].{item: item, stdout_lines: stdout_lines}') }}"

    - name: Use shell to print 'stdout_lines' per result
      shell: "echo {{ item.stdout_lines }}"
      loop: "{{ result | json_query('results[*].{item: item, stdout_lines: stdout_lines}') }}"

    - name: Use shell to print flattened 'stdout_lines'
      shell: "echo {{ item }}"
      loop: "{{ result | json_query('results[*].{stdout_lines: stdout_lines}') }}"

Hopefully someone finds this useful.
Reply all
Reply to author
Forward
0 new messages