Ansible: How to delete files and folders inside a directory?

Mohan Kumar P

Below code will delete the entire contents of artifact_path

- name: Clean artifact path
    state: absent
    path: "{{ artifact_path }}/"

Note: this will delete the directory too.

Using shell module (idempotent too):

- shell: /bin/rm -rf /home/mydata/web/*

Cleanest solution if you don't care about creation date and owner/permissions:

- file: path=/home/mydata/web state=absent
- file: path=/home/mydata/web state=directory

Remove the directory (basically a copy of, Ansible does this operation with rmtree under the hood.

- name: remove files and directories
    state: "{{ item }}"
    path: "/srv/deleteme/"
    owner: 1000  # set your owner, group, and mode accordingly
    group: 1000
    mode: '0777'
    - absent
    - directory

If you don't have the luxury of removing the whole directory and recreating it, you can scan it for files, (and directories), and delete them one by one. Which will take a while. You probably want to make sure you have [ssh_connection]\npipelining = True in your ansible.cfg on.

- block:
  - name: 'collect files'
      paths: "/srv/deleteme/"
      hidden: True
      recurse: True
      # file_type: any  # Added in ansible 2.3
    register: collected_files

  - name: 'collect directories'
      paths: "/srv/deleteme/"
      hidden: True
      recurse: True
      file_type: directory
    register: collected_directories

  - name: remove collected files and directories
      path: "{{ item.path }}"
      state: absent
    with_items: >
        + collected_directories.files
Ganesan Srinivasan

try the below command, it should work

- shell: ls -1 /some/dir
  register: contents

- file: path=/some/dir/{{ item }} state=absent
  with_items: {{ contents.stdout_lines }}

I really didn't like the rm solution, also ansible gives you warnings about using rm. So here is how to do it without the need of rm and without ansible warnings.

- hosts: all
  - name: Ansible delete file glob
      paths: /etc/Ansible
      patterns: "*.txt"
    register: files_to_delete

  - name: Ansible remove file glob
      path: "{{ item.path }}"
      state: absent
    with_items: "{{ files_to_delete.files }}"


Created an overall rehauled and fail-safe implementation from all comments and suggestions:

# collect stats about the dir
- name: check directory exists
    path: '{{ directory_path }}'
  register: dir_to_delete

# delete directory if condition is true
- name: purge {{directory_path}}
    state: absent
    path: '{{ directory_path  }}'
  when: dir_to_delete.stat.exists and dir_to_delete.stat.isdir

# create directory if deleted (or if it didn't exist at all)
- name: create directory again
    state: directory
    path: '{{ directory_path }}'
  when: dir_to_delete is defined or dir_to_delete.stat.exist == False

Using file glob also it will work. There is some syntax error in the code you posted. I have modified and tested this should work.

- name: remove web dir contents
    path: "{{ item }}"
    state: absent
    - "/home/mydata/web/*"

While Ansible is still debating to implement state = empty

my_folder: "/home/mydata/web/"
empty_path: "/tmp/empty"

- name: "Create empty folder for wiping."
    path: "{{ empty_path }}" 
    state: directory

- name: "Wipe clean {{ my_folder }} with empty folder hack."
    mode: push

    #note the backslash here
    src: "{{ empty_path }}/" 

    dest: "{{ nl_code_path }}"
    recursive: yes
    delete: yes
  delegate_to: "{{ inventory_hostname }}"

Note though, with synchronize you should be able to sync your files (with delete) properly anyway.


There is an issue open with respect to this.

For now, the solution works for me: create a empty folder locally and synchronize it with the remote one.

Here is a sample playbook:

- name: "Empty directory"
  hosts: *
    - name: "Create an empty directory (locally)"
        module: file
        state: directory
        path: "/tmp/empty"

    - name: Empty remote directory
        src: /tmp/empty/
        dest: /home/mydata/web/
        delete: yes
        recursive: yes

I want to make sure that the find command only deletes everything inside the directory and leave the directory intact because in my case the directory is a filesystem. The system will generate an error when trying to delete a filesystem but that is not a nice option. Iam using the shell option because that is the only working option I found so far for this question.

What I did:

Edit the hosts file to put in some variables:


And create a playbook:

- hosts: all
  - name: Ansible remove files
    shell: "{{ find }} {{ COGNOS_HOME }} -xdev -mindepth 1 -delete"

This will delete all files and directories in the COGNOS_HOME variable directory/filesystem. The "-mindepth 1" option makes sure that the current directory will not be touched.


I have written an custom ansible module to cleanup files based on multiple filters like age, timestamp, glob patterns, etc.

It is also compatible with ansible older versions. It can be found here.

Here is an example:

- cleanup_files:
  path_pattern: /tmp/*.log
  state: absent
    - foo*
    - bar*

Just a small cleaner copy & paste template of ThorSummoners answer, if you are using Ansible >= 2.3 (distinction between files and dirs not necessary anymore.)

- name: Collect all fs items inside dir
    path: "{{ target_directory_path }}"
    hidden: true
    file_type: any
  changed_when: false
  register: collected_fsitems
- name: Remove all fs items inside dir
    path: "{{ item.path }}"
    state: absent
  with_items: "{{ collected_fsitems.files }}"
  when: collected_fsitems.matched|int != 0

That's what I come up with:

- name: Get directory listing
    path: "{{ directory }}" 
    file_type: any
    hidden: yes
  register: directory_content_result

- name: Remove directory content
    path: "{{ item.path }}" 
    state: absent
  with_items: "{{ directory_content_result.files }}" 
    label: "{{ item.path }}" 

First, we're getting directory listing with find, setting

  • file_type to any, so we wouldn't miss nested directories and links
  • hidden to yes, so we don't skip hidden files
  • also, do not set recurse to yes, since it is not only unnecessary, but may increase execution time.

Then, we go through that list with file module. It's output is a bit verbose, so loop_control.label will help us with limiting output (found this advice here).

But I found previous solution to be somewhat slow, since it iterates through the content, so I went with:

- name: Get directory stats
    path: "{{ directory }}"
  register: directory_stat

- name: Delete directory
    path: "{{ directory }}"
    state: absent

- name: Create directory
    path: "{{ directory }}"
    state: directory
    owner: "{{ directory_stat.stat.pw_name }}"
    group: "{{ directory_stat.stat.gr_name }}"
    mode: "{{ directory_stat.stat.mode }}"
  • get directory properties with the stat
  • delete directory
  • recreate directory with the same properties.

That was enough for me, but you can add attributes as well, if you want.

Assuming you are always in Linux, try the find cmd.

- name: Clean everything inside {{ item }}
  shell: test -d {{ item }} && find {{ item }} -path '{{ item }}/*' -prune -exec rm -rf {} \;
  with_items: [/home/mydata/web]

This should wipe out files/folders/hidden under /home/mydata/web

  - name: delete old data and clean cache
      path: "{{ item[0] }}" 
      state: "{{ item[1] }}"
      - [ "/data/server/{{ app_name }}/webapps/", "/data/server/{{ app_name }}/work/" ]
      - [ "absent", "directory" ]
    ignore_errors: yes

This is my example.

  1. Install repo
  2. Install rsyslog package
  3. stop rsyslog
  4. delete all files inside /var/log/rsyslog/
  5. start rsyslog

    - hosts: all
        - name: Install rsyslog-v8 yum repo
            src: files/rsyslog.repo
            dest: /etc/yum.repos.d/rsyslog.repo
        - name: Install rsyslog-v8 package
            name: rsyslog
            state: latest
        - name: Stop rsyslog
            name: rsyslog
            state: stopped
        - name: cleann up /var/spool/rsyslog
          shell: /bin/rm -rf /var/spool/rsyslog/*
        - name: Start rsyslog
            name: rsyslog
            state: started

Below worked for me,

- name: Ansible delete html directory
   path: /var/www/html
   state: directory