Skip to content

Fileglob Lookup — Finding Matching Files


When you need to discover files dynamically, fileglob gives you a simple way to match paths against a pattern and work with the files it finds. Understanding how it matches files, returns results, and fits into common automation patterns makes it much easier to use effectively.

What fileglob Actually Does

fileglob matches files on the control node’s filesystem against a glob pattern — *.conf, for instance — and returns the paths of every match. Not their contents, just the paths themselves; that distinction matters directly against the file lookup from earlier in this section, which reads content, not paths.

Basic Usage

msg: "{{ lookup('fileglob', '*.conf', wantlist=true) }}"
['app.conf', 'db.conf', 'cache.conf']

Combining fileglob With loop:

A list of matching paths is exactly what loop: wants:

- name: "Report config file: {{ item }}"
  ansible.builtin.debug:
    msg: "Found config file: {{ item }}"
  loop: "{{ lookup('fileglob', '*.conf', wantlist=true) }}"

A Realistic Example: Processing Every Config File In A Directory

Combining fileglob with copy, pushing every locally-matched file up to the remote host:

copy_configs.yaml
- name: "Copy config: {{ item }}"
  ansible.builtin.copy:
    src: "{{ item }}"
    dest: "/etc/app/{{ item | basename }}"
  loop: "{{ lookup('fileglob', 'configs/*.conf', wantlist=true) }}"

basename, new here, extracts just the filename from a full path — needed since fileglob hands back complete paths (configs/app.conf), but the remote destination should just be the filename itself (app.conf), not the local directory structure alongside it.

The wantlist=true Detail, Explained Properly

Here’s exactly why that argument matters, made concrete. Without it:

msg: "{{ lookup('fileglob', '*.conf') }}"
app.conf,db.conf,cache.conf

That’s a single comma-joined string, not a list — lookup()’s plain default behavior, when there’s more than one match, is to glue every result together into one string rather than return a genuine list. Feed that directly into loop: without wantlist=true, and you’d get exactly one iteration, with item holding that entire joined string — not three separate iterations the way you’d want.

msg: "{{ lookup('fileglob', '*.conf', wantlist=true) }}"
['app.conf', 'db.conf', 'cache.conf']

wantlist=true forces a genuine list back, regardless of how many matches there are — even a single match becomes a proper one-element list rather than a bare string. This is exactly the detail glossed over back in the loops section, now fully explained.

A Gotcha: Glob Patterns Are Relative To The Playbook, Same As file

The exact same rule from Chapter 2’s file lookup applies here too — a relative glob pattern resolves against the playbook’s own location, not your shell’s current working directory, however far from the playbook you happen to be running ansible-playbook from.

Best Practices

  • Always use wantlist=true with fileglob — and really, with any lookup you intend to feed into loop: — never rely on the default comma-joined-string behavior.
  • Combine fileglob with basename (or another path filter) when you need just the filename, not the full control-node path, for use on the remote side.
  • Remember fileglob patterns resolve relative to the playbook’s location, exactly like the file lookup.
Last updated on