Debugging multiple ansible_loop_var:item inside stdout_lines in a looping task

Hello. How do I successfully debug just an stdout_lines in a task that has more than one variable to debug? I can only run it for a non-looping task, with just one value to debug.

I have a playbook that does the following. It connects to an Oracle database server and checks if a directory /dcr is empty. If it is, it does nothing. If it has one or more Data Request Change (DCR) scripts, it executes them one after another. The last step is to debug the script run. I only want the stdout_lines debugged, not the entire variable.

If I write a task with just one named file to run, I can get the stdout_lines just fine.

         - name: Run the ONE DCR script | {{ ansible_date_time.iso8601 }}
            ansible.builtin.shell: 
              cmd: "{{ scratchpad }}/dcr1.sh"
            register: run_dcr_out
            become: true
            become_user: oracle
            become_method: su 
            become_flags: "--login"
            ignore_errors: true
            when: directory_contents_check.matched > 0

          - name: Export GoldenGate facts for each deployment | Add a GoldenGate Deployment
#            debug: var=run_dcr_out
            debug: var=run_dcr_out.stdout_lines

and the output is:

TASK [Run the ONE DCR script | {{ ansible_date_time.iso8601 }}] ************************************************************************************************************************
changed: [192.168.1.202]

TASK [Export GoldenGate facts for each deployment | Add a GoldenGate Deployment] *******************************************************************************************************
ok: [192.168.1.202] => 
  run_dcr_out.stdout_lines:
  - /u03/ogg/bin
  - GoldenGate binaries  /u03/ogg/bin
  - Report file          /ogg_depl_001/var/lib/report/
  - Parameter file       /ogg_depl_001/etc/conf/ogg/
  - Error log            /ogg_depl_001/var/log/ggserr.log
  - "Dirdat\t\t     /ogg_depl_001/var/lib/data/"
  - Adminclient          /u03/ogg/bin/adminclient
  - ''
  - Session altered.
  - ''
  - ''
  - NAME
  - '---------'
  - CDB1
  - ''
  - ''
  - Commit complete.

PLAY RECAP *****************************************************************************************************************************************************************************
192.168.1.202              : ok=6    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

However, in a more practical incarnation , where there isnt a fixed named script to run and more than one script in the /dcr directory, the same fails (two scripts present below, dcr1.sh and dcr2.sh):

[oracle@lnx001 dcr]$ pwd
/dcr
[oracle@lnx001 dcr]$ ls -ltr
total 8
-rwxrwxrwt. 1 oracle oinstall 162 Jan 22 18:53 dcr1.sh
-rwxrwxrwt. 1 oracle oinstall 183 Jan 22 18:54 dcr2.sh
[oracle@lnx001 dcr]$

           - name: 1. Find all executable scripts in the directory
              ansible.builtin.find:
                paths: "{{scratchpad}}"
                patterns: "*.sh"
                recurse: yes
                file_type: file
              register: directory_contents_check 

            - name: Debug message if the directory is empty
              ansible.builtin.debug:
                msg: "The DCR directory {{scratchpad}} is empty."
              when: directory_contents_check.matched == 0

            - name: Debug message if the directory is NOT empty
              ansible.builtin.debug:
                msg: "The DCR directory {{scratchpad}} is NOT empty, ({{ directory_contents_check.matched }} Oracle DCR scripts found)."
              when: directory_contents_check.matched > 0

            - name: 2. Run each DCR script in order
              ansible.builtin.shell: 
                cmd: "{{ item.path }}"
              loop: "{{ directory_contents_check.files }}" 
              loop_control:
                label: "Running script: {{ item.path }}" 
              become: true
              become_user: oracle
              become_method: su 
              become_flags: "--login"
              ignore_errors: true
              register: run_dcr_out
              when: directory_contents_check.matched > 0

            - name: Export GoldenGate facts for each deployment | Add a GoldenGate Deployment
              debug: var=run_dcr_out.stdout_lines

and the output is:

          [ansible_admin@lnx000 ansible]$ ansible-playbook ./playbooks/dcr4.yml 
[WARNING]: Ansible is being run in a world writable directory (/etc/ansible), ignoring it as an ansible.cfg source. For more information see
https://docs.ansible.com/ansible/devel/reference_appendices/config.html#cfg-in-world-writable-dir
/usr/lib/python3.6/site-packages/requests/__init__.py:91: RequestsDependencyWarning: urllib3 (1.26.20) or chardet (3.0.4) doesn't match a supported version!
  RequestsDependencyWarning)

PLAY [Oracle GoldenGate replicat down, out of sync Process ID 2872.56] *****************************************************************************************************************

TASK [Check if a Lockfile exists | itsm_dcr] *******************************************************************************************************************************************
ok: [192.168.1.202]

TASK [Debug the GoldenGate Change Request data ogg_cr_custom_out | itsm_dcr] ***********************************************************************************************************
ok: [192.168.1.202] => 
  msg: No prior run lockfile present, starting the DCR

TASK [Create Lockfile if Doesnt Exist | itsm_dcr] **************************************************************************************************************************************
changed: [192.168.1.202]

TASK [1. Find all executable scripts in the directory] *********************************************************************************************************************************
ok: [192.168.1.202]

TASK [Debug message if the directory is empty] *****************************************************************************************************************************************
skipping: [192.168.1.202]

TASK [Debug message if the directory is NOT empty] *************************************************************************************************************************************
ok: [192.168.1.202] => 
  msg: The DCR directory /dcr is NOT empty, (2 Oracle DCR scripts found).

TASK [2. Run each DCR script in order] *************************************************************************************************************************************************
changed: [192.168.1.202] => (item=Running script: /dcr/dcr1.sh)
changed: [192.168.1.202] => (item=Running script: /dcr/dcr2.sh)

TASK [Export GoldenGate facts for each deployment | Add a GoldenGate Deployment] *******************************************************************************************************
ok: [192.168.1.202] => 
  run_dcr_out.stdout_lines: VARIABLE IS NOT DEFINED!

TASK [Remove the Lockfile after the DCR completion | itsm_dcr] *************************************************************************************************************************
changed: [192.168.1.202]

PLAY RECAP *****************************************************************************************************************************************************************************
192.168.1.202              : ok=8    changed=3    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0 

if I change the “var=run_dcr_out.stdout_lines” to “var=run_dcr_out”, it runs fine, but debugs the entire variable, which I do not need. I just need the Oracle output in the “stdout_lines”.

Here is the entire playbook:

---
    - name: Oracle Data Change Request Process ID 2872.56
      hosts: dbservers
      gather_facts: false
      vars_files:
        - vars/main.yml

      tasks:

############################### lockfile####################################

        - name: Check if a Lockfile exists | itsm_dcr
          stat:
            path: "{{ scratchpad }}/lockfile"
          register: prior_run_lockfile_out   

        - name: Proceed with the current DCR if a lockfile is absent | itsm_dcr
          when: 
#            - new_ogg_cr_custom_out['records'] | default([]) | length > 0
            - not prior_run_lockfile_out.stat.exists
          block:

            - name: Debug the GoldenGate Change Request data ogg_cr_custom_out | itsm_dcr 
              ansible.builtin.debug:
                msg: "No prior run lockfile present, starting the DCR"

            - name: Create Lockfile if Doesnt Exist | itsm_dcr
              ansible.builtin.file:
                path: "{{ scratchpad }}/lockfile"
                state: touch
                mode: '0644'

############################################################################

            - name: 1. Find all executable scripts in the directory
              ansible.builtin.find:
                paths: "{{scratchpad}}"
                patterns: "*.sh"
                recurse: yes
                file_type: file
              register: directory_contents_check 

            - name: Debug message if the directory is empty
              ansible.builtin.debug:
                msg: "The DCR directory {{scratchpad}} is empty."
              when: directory_contents_check.matched == 0

            - name: Debug message if the directory is NOT empty
              ansible.builtin.debug:
                msg: "The DCR directory {{scratchpad}} is NOT empty, ({{ directory_contents_check.matched }} Oracle DCR scripts found)."
              when: directory_contents_check.matched > 0

            - name: 2. Run each DCR script in order
              ansible.builtin.shell: 
                cmd: "{{ item.path }}"
              loop: "{{ directory_contents_check.files }}" 
              loop_control:
                label: "Running script: {{ item.path }}" 
              become: true
              become_user: oracle
              become_method: su 
              become_flags: "--login"
              ignore_errors: true
              register: run_dcr_out
              when: directory_contents_check.matched > 0

            - name: Export GoldenGate facts for each deployment | Add a GoldenGate Deployment
              debug: var=run_dcr_out

            - name: Remove the Lockfile after the DCR completion | itsm_dcr
              ansible.builtin.file:
                path: "{{ scratchpad }}/lockfile"
                state: absent
                mode: '0644'

######################

and the output:

TASK [1. Find all executable scripts in the directory] *********************************************************************************************************************************
ok: [192.168.1.202]

TASK [Debug message if the directory is empty] *****************************************************************************************************************************************
skipping: [192.168.1.202]

TASK [Debug message if the directory is NOT empty] *************************************************************************************************************************************
ok: [192.168.1.202] => 
  msg: The DCR directory /dcr is NOT empty, (2 Oracle DCR scripts found).

TASK [2. Run each DCR script in order] *************************************************************************************************************************************************
changed: [192.168.1.202] => (item=Running script: /dcr/dcr1.sh)
changed: [192.168.1.202] => (item=Running script: /dcr/dcr2.sh)

TASK [Export GoldenGate facts for each deployment | Add a GoldenGate Deployment] *******************************************************************************************************
ok: [192.168.1.202] => 
  run_dcr_out:
    changed: true
    msg: All items completed
    results:
    - ansible_loop_var: item
      changed: true
      cmd: /dcr/dcr1.sh
      delta: '0:00:00.223861'
      end: '2026-01-23 15:39:23.990845'
      failed: false
      invocation:
        module_args:
          _raw_params: /dcr/dcr1.sh
          _uses_shell: true
          argv: null
          chdir: null
          creates: null
          executable: null
          removes: null
          stdin: null
          stdin_add_newline: true
          strip_empty_ends: true
          warn: true
      item:
        atime: 1769133659.0682027
        ctime: 1769133631.4188566
        dev: 64512
        gid: 54321
        gr_name: oinstall
        inode: 136768582
        isblk: false
        ischr: false
        isdir: false
        isfifo: false
        isgid: false
        islnk: false
        isreg: true
        issock: false
        isuid: false
        mode: '1777'
        mtime: 1769126032.0
        nlink: 1
        path: /dcr/dcr1.sh
        pw_name: oracle
        rgrp: true
        roth: true
        rusr: true
        size: 162
        uid: 54321
        wgrp: true
        woth: true
        wusr: true
        xgrp: true
        xoth: true
        xusr: true
      rc: 0
      start: '2026-01-23 15:39:23.766984'
      stderr: ''
      stderr_lines: []
      stdout: |-
        /u03/ogg/bin
        GoldenGate binaries  /u03/ogg/bin
        Report file          /ogg_depl_001/var/lib/report/
        Parameter file       /ogg_depl_001/etc/conf/ogg/
        Error log            /ogg_depl_001/var/log/ggserr.log
        Dirdat               /ogg_depl_001/var/lib/data/
        Adminclient          /u03/ogg/bin/adminclient
  
        Session altered.
  
  
        NAME
        ---------
        CDB1
  
  
        Commit complete.
      stdout_lines:
      - /u03/ogg/bin
      - GoldenGate binaries  /u03/ogg/bin
      - Report file          /ogg_depl_001/var/lib/report/
      - Parameter file       /ogg_depl_001/etc/conf/ogg/
      - Error log            /ogg_depl_001/var/log/ggserr.log
      - "Dirdat\t\t     /ogg_depl_001/var/lib/data/"
      - Adminclient          /u03/ogg/bin/adminclient
      - ''
      - Session altered.
      - ''
      - ''
      - NAME
      - '---------'
      - CDB1
      - ''
      - ''
      - Commit complete.
    - ansible_loop_var: item
      changed: true
      cmd: /dcr/dcr2.sh
      delta: '0:00:03.495964'
      end: '2026-01-23 15:39:28.774535'
      failed: false
      invocation:
        module_args:
          _raw_params: /dcr/dcr2.sh
          _uses_shell: true
          argv: null
          chdir: null
          creates: null
          executable: null
          removes: null
          stdin: null
          stdin_add_newline: true
          strip_empty_ends: true
          warn: true
      item:
        atime: 1769133659.4441938
        ctime: 1769133631.4188566
        dev: 64512
        gid: 54321
        gr_name: oinstall
        inode: 136768584
        isblk: false
        ischr: false
        isdir: false
        isfifo: false
        isgid: false
        islnk: false
        isreg: true
        issock: false
        isuid: false
        mode: '1777'
        mtime: 1769126082.0
        nlink: 1
        path: /dcr/dcr2.sh
        pw_name: oracle
        rgrp: true
        roth: true
        rusr: true
        size: 183
        uid: 54321
        wgrp: true
        woth: true
        wusr: true
        xgrp: true
        xoth: true
        xusr: true
      rc: 0
      start: '2026-01-23 15:39:25.278571'
      stderr: ''
      stderr_lines: []
      stdout: |-
        /u03/ogg/bin
        GoldenGate binaries  /u03/ogg/bin
        Report file          /ogg_depl_001/var/lib/report/
        Parameter file       /ogg_depl_001/etc/conf/ogg/
        Error log            /ogg_depl_001/var/log/ggserr.log
        Dirdat               /ogg_depl_001/var/lib/data/
        Adminclient          /u03/ogg/bin/adminclient
  
        Session altered.
  
  
        64 rows created.
  
  
        Commit complete.
      stdout_lines:
      - /u03/ogg/bin
      - GoldenGate binaries  /u03/ogg/bin
      - Report file          /ogg_depl_001/var/lib/report/
      - Parameter file       /ogg_depl_001/etc/conf/ogg/
      - Error log            /ogg_depl_001/var/log/ggserr.log
      - "Dirdat\t\t     /ogg_depl_001/var/lib/data/"
      - Adminclient          /u03/ogg/bin/adminclient
      - ''
      - Session altered.
      - ''
      - ''
      - 64 rows created.
      - ''
      - ''
      - Commit complete.

TASK [Remove the Lockfile after the DCR completion | itsm_dcr] *************************************************************************************************************************
changed: [192.168.1.202]

PLAY RECAP *****************************************************************************************************************************************************************************
192.168.1.202              : ok=8    changed=3    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

[ansible_admin@lnx000 ansible]$ 

so, how do I get just the part I need for the looping VAR in the debugged "ansible_loop_var: item ", not just a single script run, as there may be a hundred scripts uploaded there and the debug will be unreadable with so much Ansible junk it I dont need.
Thank you in advance.
Nestor.

When you register: the output from a non-looped shell or cmd task, you get a single result containing the data about that single task.

When you loop the same task and register: its output, your registered variable contains a single changed: attribute, but it also contains a results: attribute which is a list. Each element in the registered_var.results list contains what would have been registered for each of your loop items had you run them each as a separate task.

So in your looped registered run_dcr_out: you have a run_dcr_out.results list, each item of which contains the item for that iteration of the loop as well as its own stdout and stdout_lines for that item.

You could see the results for each item like this:

    - name: Debug looped output
      ansible.builtin.debug:
        msg: |
          Script: {{ item.item.path }}
          {{ item.stdout }}
      loop: "{{ run_dcr_out.results }}"

Or you could ansible.builtin.template to write these results to a file.

You could also do something like this:

    - name: Debug looped output
      ansible.builtin.debug:
        msg: "{{ run_dcr_out.results| map(attribute=('item.path'))
                 | zip(run_dcr_out.results| map(attribute=('stdout_lines'))) }}"

which produces

  msg:
  - - /dcr/dcr1.sh
    - - /u03/ogg/bin
      - GoldenGate binaries  /u03/ogg/bin
      - Report file          /ogg_depl_001/var/lib/report/
      - Parameter file       /ogg_depl_001/etc/conf/ogg/
      - Error log            /ogg_depl_001/var/log/ggserr.log
      - "Dirdat\t\t     /ogg_depl_001/var/lib/data/"
      - Adminclient          /u03/ogg/bin/adminclient
      - ''
      - Session altered.
      - ''
      - ''
      - NAME
      - '---------'
      - CDB1
      - ''
      - ''
      - Commit complete.
  - - /dcr/dcr2.sh
    - - /u03/ogg/bin
      - GoldenGate binaries  /u03/ogg/bin
      - Report file          /ogg_depl_001/var/lib/report/
      - Parameter file       /ogg_depl_001/etc/conf/ogg/
      - Error log            /ogg_depl_001/var/log/ggserr.log
      - "Dirdat\t\t     /ogg_depl_001/var/lib/data/"
      - Adminclient          /u03/ogg/bin/adminclient
      - ''
      - Session altered.
      - ''
      - ''
      - 64 rows created.
      - ''
      - ''
      - Commit complete.

You can also use json_query like this (extracting three attributes in this case):

    - name: Debug looped output
      ansible.builtin.debug:
        msg: "{{ run_dcr_out.results
                 | json_query('[].{file: item.path,
                                   elapsed_time: delta,
                                   output: stdout_lines}') }}"

producing

ok: [localhost] => 
  msg:
  - elapsed_time: '0:00:00.223861'
    file: /dcr/dcr1.sh
    output:
    - /u03/ogg/bin
    - GoldenGate binaries  /u03/ogg/bin
    - Report file          /ogg_depl_001/var/lib/report/
    - Parameter file       /ogg_depl_001/etc/conf/ogg/
    - Error log            /ogg_depl_001/var/log/ggserr.log
    - "Dirdat\t\t     /ogg_depl_001/var/lib/data/"
    - Adminclient          /u03/ogg/bin/adminclient
    - ''
    - Session altered.
    - ''
    - ''
    - NAME
    - '---------'
    - CDB1
    - ''
    - ''
    - Commit complete.
  - elapsed_time: '0:00:03.495964'
    file: /dcr/dcr2.sh
    output:
    - /u03/ogg/bin
    - GoldenGate binaries  /u03/ogg/bin
    - Report file          /ogg_depl_001/var/lib/report/
    - Parameter file       /ogg_depl_001/etc/conf/ogg/
    - Error log            /ogg_depl_001/var/log/ggserr.log
    - "Dirdat\t\t     /ogg_depl_001/var/lib/data/"
    - Adminclient          /u03/ogg/bin/adminclient
    - ''
    - Session altered.
    - ''
    - ''
    - 64 rows created.
    - ''
    - ''
    - Commit complete.
3 Likes

@utoddl thank you for the detailed and helpful solution. I will work on its implementation.
Appreciate your help very much. Have a great weekend.
Nestor Kandinsky-Clerambeau.