# Help with Ansible loop

**URL:** <https://forum.ansible.com/t/help-with-ansible-loop/43598>\
**Category:** Get Help\
**Tags:** rhel\
**Created:** [June 27, 2025, 1:03pm UTC](https://forum.ansible.com/t/help-with-ansible-loop/43598 "2025-06-27T13:03:22Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![trt757](https://avatars.discourse-cdn.com/v4/letter/t/c67d28/32.png) [@trt757](https://forum.ansible.com/u/trt757)\
**Post date:** [June 27, 2025, 1:03pm UTC](https://forum.ansible.com/t/help-with-ansible-loop/43598/1 "2025-06-27T13:03:22Z")

</div>

So I have a directory on a rhel 8 server, that has directories in it, that result from a role that does a fetch from workstations (flat: true) so the directories are named for the hosts two files come from. I’m pulling over a “hostname”.req file and a “hostname”.csr file. I’m trying to loop through each of these directories (and to make it easier and quicker I’ve cut down the number of host directories to just two for now.) and run a shell command. Below is the playbook that eventually I’ll configure as a role within a much larger playbook.

Note: Any spelling mistakes or indentation mistakes are just from typing. The playbook runs on a closed network.

- name: Get directory names  
ansbible.builtin.find:  
paths: /etc/cert\_dir/workstations  
file\_type: directory  
register: hostname

### The above I hope to use later in the play to name a created crt file {{ hostname }}.crt But for now I’m satisfied that ansible can descend into the main dir and enumerate the two host dirs. I have another play after this that uses "set\_fact: dir\_name: “{{ hostname.files | map(attribute=‘path’) |map(‘basename’) | list }}” This is just experimenting with saving/using variables.

- name: Print hostname  
ansible.builtin.debug  
msg: "the hostnames are: {{ hostname }} ## Comment: so far so good. Just a sanity check  
that ansible can descend into my main folder  
and enumerate the directories there.

- name: Find CSR files  
ansible.builtin.find:  
paths: /etc/cert\_dir/workstations  
file\_type: file  
patterns: “\*.csr”  
recurse: yes  
register: csr

### I have another section that prints the csr files found. It works. it shows host1.csr and host2.csr (not in a list like I thought it would be, but in a comma-separted paragraph. Ok, that works). This will be removed later since it’s just a sanity check for me - can ansible find all these files? Yes it can - ok all good.

## Here’s the part I’m having trouble with:

- name: Test variable usage against the found csr files  
ansible.builtin.shell:  
cmd: openssl req -text -noout -verify -in {{ csr }} {{ item.path }}  
with\_items: “{{ csr.files }}”  
register: command\_output # So I can see the output of the openssl verify command. Following this is just a simple print “command\_output” to the display

I get a big block of red text for the two csr files. It’s too much to type here, that whole error message. Part of it is: /etc/cert\_dir/workstations/host1.csr, ‘mode’: 0777, isdir: False, 'ischr: False… and it just goes on and on for awhile listing things that don’t seem useful. I just don’t get what I’m doing wrong.

I’ve tried several different ways of coding the last part of the play above. At first I was using:  
loop: {{ csr.files |map(attribute=‘path’) }}" ## same result though.

---

<div class="post-metadata">

**Author:** ![trt757](https://avatars.discourse-cdn.com/v4/letter/t/c67d28/32.png) [@trt757](https://forum.ansible.com/u/trt757)\
**Post date:** [June 27, 2025, 1:05pm UTC](https://forum.ansible.com/t/help-with-ansible-loop/43598/2 "2025-06-27T13:05:09Z")

</div>

I’ve been trying to read and understand what this does: {{ item.path }} and whether it should go in the play just like that, or whether I need to replace that with the path to my files?

---

<div class="post-metadata">

**Author:** ![trt757](https://avatars.discourse-cdn.com/v4/letter/t/c67d28/32.png) [@trt757](https://forum.ansible.com/u/trt757)\
**Post date:** [June 27, 2025, 2:22pm UTC](https://forum.ansible.com/t/help-with-ansible-loop/43598/3 "2025-06-27T14:22:20Z")

</div>

I’ve realized what I’m doing wrong, still trying to fix it.

I realized that these plays:

- name: Find CSR files  
ansible.builtin.find:  
paths: /etc/cert\_dir/workstations  
file\_type: file  
patterns: “\*.csr”  
recurse: yes  
register: csr

- name: Print csr variable  
debug:  
msg: Print result of CSR search: {{ csr }}

This produces a paragraph for each csr file name, but also includes a lot of file attributes which I realized is probably being passed into the shell command.

So I added this:

- name: Find CSR files  
ansible.builtin.find:  
paths: /etc/cert\_dir/workstations  
file\_type: file  
patterns: “\*.csr”  
recurse: yes  
register: csr

- name: csr file names into new variable  
set\_fact:  
CSR: “{{csr.files | map(attribute=‘path’) | map(‘basename’) | list }}”

- name: Print csr variable  
debug:  
msg: Print result of CSR search: {{ CSR }}

Now I get just the two files names, without all the attributes. But if I pass this new variable “CSR” to my openssl verify command, I’m getting "the task includes an option with an undefined variable. This is after I’ve replaced “csr” in the shell command with “CSR”

---

<div class="post-metadata">

**Author:** ![shertel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/shertel/32/1241_2.png) [@shertel](https://forum.ansible.com/u/shertel)\
**Post date:** [June 27, 2025, 5:27pm UTC](https://forum.ansible.com/t/help-with-ansible-loop/43598/4 "2025-06-27T17:27:16Z")

</div>

I’m not sure why CSR would be undefined without more context. The snippet seems fine. If you use ``` on the line before and after a block of tasks, it will make it easier to read.

In your original post, why are you passing in csr to the openssl command? Couldn’t you just use the loop item?

```auto
    - name: Test variable usage against the found csr files
      ansible.builtin.shell:
        cmd: openssl req -text -noout -verify -in {{ item.path }}
      with_items: "{{ csr.files }}"
      register: command_output

```

---

<div class="post-metadata">

**Author:** ![trt757](https://avatars.discourse-cdn.com/v4/letter/t/c67d28/32.png) [@trt757](https://forum.ansible.com/u/trt757)\
**Post date:** [June 27, 2025, 5:30pm UTC](https://forum.ansible.com/t/help-with-ansible-loop/43598/5 "2025-06-27T17:30:40Z")

</div>

> [@trt757](#):
>
> name: Test variable usage against the found csr files  
> ansible.builtin.shell:  
> cmd: openssl req -text -noout -verify -in {{ csr }} {{ item.path }}  
> with\_items: “{{ csr.files }}”  
> register: command\_output # So I can see the output of the openssl verify command. Following this is just a simple print “command\_output” to the display

I’ve tried it both ways: without the “with\_items” line and replaced with…  
loop: {{ csr.files | map(attribute=‘path’) | map(‘basename’) | | list }}"  
I’ve also tried:  
loop: {{CSR}}

---

<div class="post-metadata">

**Author:** ![shertel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/shertel/32/1241_2.png) [@shertel](https://forum.ansible.com/u/shertel)\
**Post date:** [June 27, 2025, 5:31pm UTC](https://forum.ansible.com/t/help-with-ansible-loop/43598/6 "2025-06-27T17:31:42Z")

</div>

The loop looks fine. The issue is the command you’re passing to openssl, can you try my suggestion?

---

<div class="post-metadata">

**Author:** ![trt757](https://avatars.discourse-cdn.com/v4/letter/t/c67d28/32.png) [@trt757](https://forum.ansible.com/u/trt757)\
**Post date:** [June 27, 2025, 5:34pm UTC](https://forum.ansible.com/t/help-with-ansible-loop/43598/7 "2025-06-27T17:34:22Z")

</div>

I’m not sure what you mean when you say “loop item”

---

<div class="post-metadata">

**Author:** ![shertel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/shertel/32/1241_2.png) [@shertel](https://forum.ansible.com/u/shertel)\
**Post date:** [June 27, 2025, 5:40pm UTC](https://forum.ansible.com/t/help-with-ansible-loop/43598/8 "2025-06-27T17:40:07Z")

</div>

It’s the dynamic value provided by the `loop`/`with_*` keyword, which requires a list. A list is made up of items.

Your original task looks like:

```auto
    - name: Test variable usage against the found csr files
      ansible.builtin.shell:
        cmd: openssl req -text -noout -verify -in {{ csr }} {{ item.path }}
      with_items: "{{ csr.files }}"
      register: command_output

```

There’s nothing wrong with the loop, only the cmd argument, try:

```auto
    - name: Test variable usage against the found csr files
      ansible.builtin.shell:
        cmd: openssl req -text -noout -verify -in {{ item.path }}
        # or maybe
        # cmd: openssl req -text -noout -verify -in {{ item.path | basename }}
      with_items: "{{ csr.files }}"
      register: command_output

```

Typically the loop variable is called “item”, but you can configure this:

```auto
    - name: Test variable usage against the found csr files
      ansible.builtin.shell:
        cmd: openssl req -text -noout -verify -in {{ csr_item.path }}
      loop: "{{ csr.files }}"
      loop_control:
        loop_var: csr_item
      register: command_output

```

Check out [Loops — Ansible Community Documentation](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#loops) for more loop features.
