AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

ansible.builtin.find Module: Search Files by Pattern, Size & Age (Guide)

By Luca Berton · Published 2024-01-01 · Category: troubleshooting

How to find files with Ansible find module (ansible.builtin.find). Search by extension, name pattern, size, age, type.

ansible.builtin.find Module: Search Files by Pattern, Size & Age (Guide)

How to Find All Files with a specific Extension with Ansible?

I'm going to show you a live Playbook with some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible Pilot.

See also: Ansible Search String in File: lineinfile & regex Guide

Ansible Find All Files with Extension

ansible.builtin.find • Return a list of files based on specific criteria

Today we're talking about the Ansible module find. The full name is ansible.builtin.find, which means that is part of the collection included in the ansible-core builtin collection. This module returns a list of files based on specific criteria using the find popular Unix command.

Parameters

• paths string - List of paths of directories to search • hidden boolean - no/yes • recurse boolean - recursively descend into the directory looking for files • file_type string - file/directory/any/link • patterns list - search (shell or regex) pattern(s) • use_regex boolean - no/yes - file globs (shell) / python regexes

The most important parameters of the find module for this use case. The mandatory parameter paths specify the list of paths of directories to search. You could include hidden files with the hidden parameter. As well as recurse in any directory under the main path with the recurse parameter. Another useful parameter is file_type, which defaults to file but you could filter for directory, link, or any filesystem object type. Specify what to search under the patterns list. Ansible by default uses file globs (shell) patterns but you could specify also python regexes enabling the use_regex parameter.

See also: Ansible Delete File: Remove Files & Directories (state=absent Guide)

Links

ansible.builtin.find

Playbook

How to Find All Files with Extension with Ansible Playbook. I'm going to search only the files and directories under the example folder of my login users (devops) and list all the files with the ".cnf" extension. This code has no dangerous effect on the target machine.

code

---
- name: find Playbook
  hosts: all
  vars:
    mypath: "/home/devops/example"
    mypattern: '*.cnf'
  tasks:
    - name: search files
      ansible.builtin.find:
        paths: "{{ mypath }}"
        hidden: true
        recurse: true
        file_type: any
        patterns: "{{ mypattern }}"
      register: found_files

- name: print files ansible.builtin.debug: var: found_files

execution

$ ansible-playbook -i virtualmachines/demo/inventory file_management/file_find.yml
PLAY [find Playbook] **********************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [search files] *******************************************************************************
ok: [demo.example.com]
TASK [print files] ********************************************************************************
ok: [demo.example.com] => {
    "found_files": {
        "changed": false,
        "examined": 3,
        "failed": false,
        "files": [
            {
                "atime": 1657183703.9653573,
                "ctime": 1657183703.9653573,
                "dev": 64768,
                "gid": 10,
                "gr_name": "wheel",
                "inode": 134965918,
                "isblk": false,
                "ischr": false,
                "isdir": false,
                "isfifo": false,
                "isgid": false,
                "islnk": false,
                "isreg": true,
                "issock": false,
                "isuid": false,
                "mode": "0644",
                "mtime": 1657183703.9653573,
                "nlink": 1,
                "path": "/home/devops/example/file1.cnf",
                "pw_name": "devops",
                "rgrp": true,
                "roth": true,
                "rusr": true,
                "size": 0,
                "uid": 1001,
                "wgrp": false,
                "woth": false,
                "wusr": true,
                "xgrp": false,
                "xoth": false,
                "xusr": false
            },
            {
                "atime": 1657183705.7742639,
                "ctime": 1657183705.7742639,
                "dev": 64768,
                "gid": 10,
                "gr_name": "wheel",
                "inode": 134965931,
                "isblk": false,
                "ischr": false,
                "isdir": false,
                "isfifo": false,
                "isgid": false,
                "islnk": false,
                "isreg": true,
                "issock": false,
                "isuid": false,
                "mode": "0644",
                "mtime": 1657183705.7742639,
                "nlink": 1,
                "path": "/home/devops/example/file2.cnf",
                "pw_name": "devops",
                "rgrp": true,
                "roth": true,
                "rusr": true,
                "size": 0,
                "uid": 1001,
                "wgrp": false,
                "woth": false,
                "wusr": true,
                "xgrp": false,
                "xoth": false,
                "xusr": false
            }
        ],
        "matched": 2,
        "msg": "All paths examined",
        "skipped_paths": {}
    }
}
PLAY RECAP ****************************************************************************************
demo.example.com           : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

idempotency

$ ansible-playbook -i virtualmachines/demo/inventory file_management/file_find.yml
PLAY [find Playbook] **********************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [search files] *******************************************************************************
ok: [demo.example.com]
TASK [print files] ********************************************************************************
ok: [demo.example.com] => {
    "found_files": {
        "changed": false,
        "examined": 3,
        "failed": false,
        "files": [
            {
                "atime": 1657183703.9653573,
                "ctime": 1657183703.9653573,
                "dev": 64768,
                "gid": 10,
                "gr_name": "wheel",
                "inode": 134965918,
                "isblk": false,
                "ischr": false,
                "isdir": false,
                "isfifo": false,
                "isgid": false,
                "islnk": false,
                "isreg": true,
                "issock": false,
                "isuid": false,
                "mode": "0644",
                "mtime": 1657183703.9653573,
                "nlink": 1,
                "path": "/home/devops/example/file1.cnf",
                "pw_name": "devops",
                "rgrp": true,
                "roth": true,
                "rusr": true,
                "size": 0,
                "uid": 1001,
                "wgrp": false,
                "woth": false,
                "wusr": true,
                "xgrp": false,
                "xoth": false,
                "xusr": false
            },
            {
                "atime": 1657183705.7742639,
                "ctime": 1657183705.7742639,
                "dev": 64768,
                "gid": 10,
                "gr_name": "wheel",
                "inode": 134965931,
                "isblk": false,
                "ischr": false,
                "isdir": false,
                "isfifo": false,
                "isgid": false,
                "islnk": false,
                "isreg": true,
                "issock": false,
                "isuid": false,
                "mode": "0644",
                "mtime": 1657183705.7742639,
                "nlink": 1,
                "path": "/home/devops/example/file2.cnf",
                "pw_name": "devops",
                "rgrp": true,
                "roth": true,
                "rusr": true,
                "size": 0,
                "uid": 1001,
                "wgrp": false,
                "woth": false,
                "wusr": true,
                "xgrp": false,
                "xoth": false,
                "xusr": false
            }
        ],
        "matched": 2,
        "msg": "All paths examined",
        "skipped_paths": {}
    }
}
PLAY RECAP ****************************************************************************************
demo.example.com           : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

before execution

$ ssh devops@demo.example.com
[devops@demo ~]$ cd example
[devops@demo example]$ ls
file1.cnf  file2.cnf  file3.txt
[devops@demo example]$ tree
.
|-- file1.cnf
|-- file2.cnf
`-- file3.txt
0 directories, 3 files
[devops@demo example]$

after execution

$ ssh devops@demo.example.com
[devops@demo ~]$ cd example
[devops@demo example]$ ls
file1.cnf  file2.cnf  file3.txt
[devops@demo example]$ tree
.
|-- file1.cnf
|-- file2.cnf
`-- file3.txt
0 directories, 3 files
[devops@demo example]$

code with ❤️ in GitHub

See also: Ansible Check If Directory Exists: stat Module Guide

Conclusion

Now you know how to Find All Files with Extension with Ansible.

Find by Extension

- ansible.builtin.find:
    paths: /var/log
    patterns: '*.log'
  register: log_files

- debug: msg: "Found {{ log_files.files | length }} log files"

Find by Multiple Extensions

- find:
    paths: /opt/myapp
    patterns:
      - '*.log'
      - '*.tmp'
      - '*.bak'
  register: cleanup_files

Find by Age

# Files older than 30 days
- find:
    paths: /var/log
    patterns: '*.log'
    age: 30d
  register: old_logs

# Files newer than 1 hour - find: paths: /tmp age: -1h register: recent_files

Find by Size

# Files larger than 100MB
- find:
    paths: /var/log
    size: 100m
  register: large_files

# Files smaller than 1KB - find: paths: /opt/configs size: -1k register: small_files

Find and Delete

# Find old temp files and remove them
- find:
    paths: /tmp
    patterns: '*.tmp'
    age: 7d
  register: old_temp

- file: path: "{{ item.path }}" state: absent loop: "{{ old_temp.files }}" become: true

- find:
    paths: /opt/myapp
    patterns: '*.conf'
    recurse: true
  register: all_configs

Find Directories

- find:
    paths: /opt
    file_type: directory
    patterns: 'cache*'
  register: cache_dirs

Find with Regex

- find:
    paths: /var/log
    patterns: 'access\.log\.\d+'
    use_regex: true
  register: rotated_logs

Find by Content (contains)

- find:
    paths: /etc/nginx/conf.d
    patterns: '*.conf'
    contains: 'server_name.*example\.com'
  register: example_configs

Find Empty Files

- find:
    paths: /var/log
    size: 0
    recurse: true
  register: empty_files

Practical: Log Rotation Cleanup

- name: Find compressed logs older than 90 days
  find:
    paths: /var/log
    patterns: '*.gz'
    age: 90d
    recurse: true
  register: old_compressed

- name: Calculate space to reclaim set_fact: space_mb: "{{ old_compressed.files | map(attribute='size') | sum / 1048576 }}"

- debug: msg: "Removing {{ old_compressed.files | length }} files ({{ space_mb | round(1) }} MB)"

- name: Remove old compressed logs file: path: "{{ item.path }}" state: absent loop: "{{ old_compressed.files }}" become: true

Practical: Find and Archive

- find:
    paths: /opt/myapp/reports
    patterns: '*.csv'
    age: 30d
  register: old_reports

- archive: path: "{{ old_reports.files | map(attribute='path') | list }}" dest: /opt/backups/old-reports.tar.gz when: old_reports.files | length > 0

Key Parameters

| Parameter | Description | |-----------|-------------| | paths | Directories to search | | patterns | Filename patterns (glob or regex) | | use_regex | Enable regex patterns | | recurse | Search subdirectories | | age | Filter by age (e.g., 30d, 1h, 2w) | | size | Filter by size (e.g., 100m, 1g) | | file_type | file, directory, link, any | | contains | Filter by file content regex | | hidden | Include hidden files | | excludes | Patterns to exclude |

FAQ

How do I use the results in a loop?

Access result.files — each item has .path, .size, .mtime, .mode:

loop: "{{ found.files }}"
msg: "{{ item.path }} ({{ item.size }} bytes)"

find vs shell find command?

The find module returns structured data (JSON), is idempotent, and cross-platform. shell: find is faster for complex queries but returns raw text.

Can I search multiple directories?

Yes: paths: [/var/log, /opt/logs, /tmp]

Find by Extension

- ansible.builtin.find:
    paths: /var/log
    patterns: "*.log"
  register: log_files

- debug: msg: "Found {{ log_files.files | length }} log files"

Find by Age

# Files older than 30 days
- find:
    paths: /var/log
    age: 30d
    recurse: true
  register: old_files

# Files newer than 1 hour - find: paths: /opt/uploads age: -1h register: new_files

Find by Size

# Files larger than 100MB
- find:
    paths: /var/log
    size: 100m
    recurse: true
  register: large_files

Find and Delete

- find:
    paths: /tmp
    patterns: "*.tmp"
    age: 7d
  register: old_tmp

- file: path: "{{ item.path }}" state: absent loop: "{{ old_tmp.files }}" become: true

Multiple Patterns

- find:
    paths: /opt/backups
    patterns:
      - "*.tar.gz"
      - "*.zip"
      - "*.bak"
    recurse: true
  register: backup_files

Find Directories

- find:
    paths: /opt
    file_type: directory
    patterns: "cache*"
  register: cache_dirs

Find by Content

- find:
    paths: /etc
    patterns: "*.conf"
    contains: "password"
    recurse: true
  register: files_with_passwords

Exclude Patterns

- find:
    paths: /var/log
    patterns: "*.log"
    excludes:
      - "*.log.gz"
      - "syslog*"
  register: active_logs

Process Found Files

- find:
    paths: /opt/myapp/data
    patterns: "*.csv"
  register: csv_files

- command: "python3 /opt/process.py {{ item.path }}" loop: "{{ csv_files.files }}"

Cleanup Playbook

- hosts: all
  become: true
  tasks:
    - find:
        paths:
          - /var/log
          - /tmp
        patterns: ["*.gz", "*.old", "*.bak"]
        age: 30d
        recurse: true
      register: cleanup_targets

- file: path: "{{ item.path }}" state: absent loop: "{{ cleanup_targets.files }}"

- debug: msg: "Cleaned {{ cleanup_targets.files | length }} files, freed {{ cleanup_targets.files | map(attribute='size') | sum | human_readable }}"

FAQ

find vs shell find command?

Ansible find is idempotent, cross-platform, and returns structured data. Use it instead of shell: find ....

How to limit results?

No built-in limit, but filter in Jinja2: {{ files.files | sort(attribute='mtime') | last }} for newest.

Can I find files across multiple directories?

Yes — paths accepts a list of directories to search.

Related Articles

Ansible inventory complete reference

Category: troubleshooting

Watch the video: ansible.builtin.find Module: Search Files by Pattern, Size & Age (Guide) — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home