5

I have a playbook that looks like this:

- hosts: host1
  gather_facts: false
  tasks:
  - name: "Loop"
    command: "echo {{ item }}"
    with_items: [ 0, 2, 4, 6, 8, 10 ]
    register: hello
  - debug: "msg={{ hello.results }}"

Everything works correctly, and the output is returned, but there is tons and tons of output. It turns out that this:

  - debug: "msg={{ hello.results.1.stdout }}"

does exactly what I want -- just grab the stdout from the command -- but only for one of the six times through the loop.

What I really want/need to do is this:

  - debug: "msg={{ hello.results.*.stdout }}"

where it goes into the hello structure, accesses the results entry, goes to each member of that array, and pulls out the stdout value.

Is this possible?


UPDATE

- hosts: host1
  gather_facts: false
  tasks:
  - name: "Loop"
    command: "echo {{ item }}"
    with_items: [ 0, 2, 4, 6, 8, 10 ]
    register: hello
  - debug:
      msg: "{{item.stdout}}"
    with_items: "{{hello.results}}"

is no less verbose than my original example.

TASK [debug] *******************************************************************
ok: [host1] => (item={'_ansible_parsed': True, 'stderr_lines': [], u'cmd': [
u'echo', u'0'], u'end': u'2018-01-02 20:53:08.916774', '_ansible_no_log': False
, u'stdout': u'0', '_ansible_item_result': True, u'changed': True, 'item': 0, 
u'delta': u'0:00:00.002137', u'stderr': u'', u'rc': 0, u'invocation': {u'module_
args': {u'warn': True, u'executable': None, u'_uses_shell': False, u'_raw_params
': u'echo 0', u'removes': None, u'creates': None, u'chdir': None, u'stdin': Non
e}}, 'stdout_lines': [u'0'], u'start': u'2018-01-02 20:53:08.914637', 'failed':
 False}) => {
    "item": {
        "changed": true,
        "cmd": [
            "echo",
            "0"
        ],
        "delta": "0:00:00.002137",
        "end": "2018-01-02 20:53:08.916774",
        "failed": false,
        "invocation": {
            "module_args": {
                "_raw_params": "echo 0",
                "_uses_shell": false,
                "chdir": null,
                "creates": null,
                "executable": null,
                "removes": null,
                "stdin": null,
                "warn": true
            }
        },
        "item": 0,
        "rc": 0,
        "start": "2018-01-02 20:53:08.914637",
        "stderr": "",
        "stderr_lines": [],
        "stdout": "0",
        "stdout_lines": [
            "0"
        ]
    },
    "msg": "0"
}

I get 6 copies of the above construct.

It feels like I'm close but I'm still doing something wrong. I see "msg": "0" at the bottom, which is what I want. I just don't want the rest of it.

1
  • Something similar confused me: In your UPDATE section, most of the output is the 'label' for each item in the loop. With Ansible now preferring loop I've put a possible workaround as an answer below with loop_control. Commented Jan 10, 2023 at 18:59

6 Answers 6

4

Solution:

- debug: "msg={{ hello.results | map(attribute='stdout') | join('\n') }}"

Remark:

By default, Ansible will print visible \n two-character sequences instead of wrapping the lines, so either use a callback plugin for a human readable output (example) or verify the method with:

- copy:
    content: "{{ hello.results | map(attribute='stdout') | join('\n') }}"
    dest: ./result.txt

and check the contents of the result.txt.

Sign up to request clarification or add additional context in comments.

2 Comments

TASK [debug] fatal: [localhost]: FAILED! => {"msg": "template error while templating string: no filter named 'map'. String: {{ hello.results | map(attribute='stdout') | join('\n') }}"} perhaps i am missing a library or an add-in or something... or perhaps my version of ansible is too old.
Fix your Ansible/Jinja2 installation. map was added in Jinja2 2.7 (in May 2013!), so your installation is either ancient, or broken.
3

I have used the keyword loop to get stdout from all iterations of the previous loop:

loop: "{{ hello | json_query('results[*].stdout') }}"

I find json_query easiest to use in such register-loop situations. Official documentation can be found here ==> json-query-filter

Comments

2

Sure. The ansible website has documentation that explains how to use register in a loop. You just need to iterate over the hello.results array, as in:

- debug:
    msg: "{{item.stdout}}"
  with_items: "{{hello.results}}"

4 Comments

If you look at the msg key in the results, you will see that it is correctly iterating over the list of results. If you want less verbose output, do something other than using a debug task.
I'm very new to ansible. Can you give me some other options? debug was the only thing I could find that generated the command's stdout.
What do you want to do with the output? Ansible isn't really a tool fir displaying things. It's a tool for doing things. Do you want to write the output to a file? Send it to another command? Etc.
I just want to log the command output, either to a file or (ideally) to a session that i can capture with script. If the tool is going to do important things, I'd need a verbose log of what it did and what the results of the commands were, for future troubleshooting/recordkeeping.
1

What about:

- debug: "msg={{ item.stdout }}"
  with_items: "{{ hello.results }}"

Comments

0

I think this construct works well enough for my needs.

- hosts: localhost
  gather_facts: false
  vars:
    stuff: [ 0,2,4,6,8,10 ]
  tasks:
  - name: "Loop"
    command: "echo {{ item }}"
    with_items: "{{ stuff }}"
    register: hello
  - debug: "var=hello.results.{{item}}.stdout"
    with_sequence: "0-{{stuff|length - 1}}"

Comments

0

I was looking at a similar problem and was confused by getting lots of output when I was expecting a relatively small msg or var from debug:. Turns out most of that output was the 'label' with which Ansible was prefixing each of those small outputs. It being a few years after this question was originally asked I've been using loop rather than with_items; this also has a label: option in loop_control:, so in my case for a similar problem - getting any /etc/passwd entries for users 'alice' or 'bob',

- hosts: all
  gather_facts: false
  serial: 1  # output easier to read when grouped by host
  tasks:
    - name: Look for users in /etc/passwd
      command: grep {{ item }} /etc/passwd
      register: res
      ignore_errors: true
      loop:
       - alice
       - bob
    - debug:
        msg: "{{ item.stdout_lines }}"
      when: not item.failed
      loop: "{{ res.results }}"
      loop_control:
        label: "{{ item.item }}"

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.