Ansible: Как удалить файлы и папки внутри каталога?
Приведенный ниже код удаляет только первый файл, который он получает внутри веб-каталога. Я хочу удалить все файлы и папки внутри веб-каталога и сохранить веб-каталог. Как я могу это сделать?
- name: remove web dir contents
file: path='/home/mydata/web/{{ item }}' state=absent
with_fileglob:
- /home/mydata/web/*
Примечание: я пробовал rm -rf
используя команду и оболочку, но они не работают. Возможно, я использую их неправильно.
Любая помощь в правильном направлении будет оценена.
Я использую ansible 2.1.0.0
26 ответов
Код ниже удалит все содержимое artifact_path
- name: Clean artifact path
file:
state: absent
path: "{{ artifact_path }}/"
Примечание: это также удалит каталог.
Удалить каталог (в основном это копия /questions/1011377/ansible-kak-udalit-fajlyi-i-papki-vnutri-kataloga/1011384#1011384), Ansible выполняет эту операцию с rmtree
под капотом.
- name: remove files and directories
file:
state: "{{ item }}"
path: "/srv/deleteme/"
owner: 1000 # set your owner, group, and mode accordingly
group: 1000
mode: '0777'
with_items:
- absent
- directory
Если у вас нет возможности удалить весь каталог и создать его заново, вы можете отсканировать его на наличие файлов (и каталогов) и удалить их один за другим. Что займет некоторое время. Вы, вероятно, хотите убедиться, что у вас есть [ssh_connection]\npipelining = True
в вашем ansible.cfg.
- block:
- name: 'collect files'
find:
paths: "/srv/deleteme/"
hidden: True
recurse: True
# file_type: any # Added in ansible 2.3
register: collected_files
- name: 'collect directories'
find:
paths: "/srv/deleteme/"
hidden: True
recurse: True
file_type: directory
register: collected_directories
- name: remove collected files and directories
file:
path: "{{ item.path }}"
state: absent
with_items: >
{{
collected_files.files
+ collected_directories.files
}}
Используя модуль оболочки:
- shell: /bin/rm -rf /home/mydata/web/*
Самое чистое решение, если вас не интересует дата создания:
- file: path=/home/mydata/web state=absent
- file: path=/home/mydata/web state=directory
Мне действительно не понравилось решение rm, также ansible дает вам предупреждения об использовании rm. Итак, вот как это сделать без необходимости использования rm и без предупреждений.
- hosts: all
tasks:
- name: Ansible delete file glob
find:
paths: /etc/Ansible
patterns: "*.txt"
register: files_to_delete
- name: Ansible remove file glob
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ files_to_delete.files }}"
источник: http://www.mydailytutorials.com/ansible-delete-multiple-files-directories-ansible/
Попробуйте команду ниже, она должна работать
- shell: ls -1 /some/dir
register: contents
- file: path=/some/dir/{{ item }} state=absent
with_items: {{ contents.stdout_lines }}
Вот что я придумал:
- name: Get directory listing
find:
path: "{{ directory }}"
file_type: any
hidden: yes
register: directory_content_result
- name: Remove directory content
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ directory_content_result.files }}"
loop_control:
label: "{{ item.path }}"
Сначала мы получаем список каталогов с find
, установка
file_type
кany
, поэтому мы не пропустим вложенные каталоги и ссылкиhidden
кyes
, поэтому мы не пропускаем скрытые файлы- также не устанавливайте
recurse
кyes
, поскольку это не только не нужно, но и может увеличить время выполнения.
Затем мы просматриваем этот список с помощью file
модуль. Его вывод немного подробен, поэтому loop_control.label
поможет нам с ограничением вывода (нашёл этот совет здесь).
Но я обнаружил, что предыдущее решение было несколько медленным, поскольку оно перебирает содержимое, поэтому я выбрал:
- name: Get directory stats
stat:
path: "{{ directory }}"
register: directory_stat
- name: Delete directory
file:
path: "{{ directory }}"
state: absent
- name: Create directory
file:
path: "{{ directory }}"
state: directory
owner: "{{ directory_stat.stat.pw_name }}"
group: "{{ directory_stat.stat.gr_name }}"
mode: "{{ directory_stat.stat.mode }}"
- получить свойства каталога с помощью
stat
- удалить каталог
- воссоздать каталог с теми же свойствами.
Мне этого было достаточно, но вы можете добавить attributes
а также, если хотите.
Использование файлового глобуса также будет работать. В опубликованном вами коде есть синтаксическая ошибка. Я изменил и проверил это должно работать.
- name: remove web dir contents
file:
path: "{{ item }}"
state: absent
with_fileglob:
- "/home/mydata/web/*"
Следуя за ответом с наибольшим количеством голосов здесь (который я не могу редактировать, так как «очередь редактирования заполнена»):
- name: Delete content & directory
file:
state: absent
path: /home/mydata/web/
- name: Re-create the directory
file:
state: directory
path: /home/mydata/web/
Пока Ansible все еще обсуждает вопрос реализации state = empty
https://github.com/ansible/ansible-modules-core/issues/902
my_folder: "/home/mydata/web/"
empty_path: "/tmp/empty"
- name: "Create empty folder for wiping."
file:
path: "{{ empty_path }}"
state: directory
- name: "Wipe clean {{ my_folder }} with empty folder hack."
synchronize:
mode: push
#note the backslash here
src: "{{ empty_path }}/"
dest: "{{ nl_code_path }}"
recursive: yes
delete: yes
delegate_to: "{{ inventory_hostname }}"
Обратите внимание, что с синхронизацией вы все равно должны иметь возможность правильно синхронизировать ваши файлы (с удалением).
Создана общая перестроенная и отказоустойчивая реализация из всех комментариев и предложений:
# collect stats about the dir
- name: check directory exists
stat:
path: '{{ directory_path }}'
register: dir_to_delete
# delete directory if condition is true
- name: purge {{directory_path}}
file:
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
file:
state: directory
path: '{{ directory_path }}'
when: dir_to_delete is defined or dir_to_delete.stat.exist == False
Ниже код работал для меня:
- name: Get directory listing
become: yes
find:
paths: /applications/cache
patterns: '*'
hidden: yes
register: directory_content_result
- name: Remove directory content
become: yes
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ directory_content_result.files }}"
Мне нравится следующее решение:
- name: remove web dir contents
command:
cmd: "find . -path '*/*' -delete -print"
chdir: "/home/mydata/web/"
register: web_files_list
changed_when: web_files_list.stdout | length > 0
потому что это так:
- простой
- идемпотент
- быстрый
В связи с этим существует открытый вопрос.
Пока решение работает для меня: создайте пустую папку локально и синхронизируйте ее с удаленной.
Вот пример книги:
- name: "Empty directory"
hosts: *
tasks:
- name: "Create an empty directory (locally)"
local_action:
module: file
state: directory
path: "/tmp/empty"
- name: Empty remote directory
synchronize:
src: /tmp/empty/
dest: /home/mydata/web/
delete: yes
recursive: yes
Я написал специальный модуль для очистки файлов на основе нескольких фильтров, таких как возраст, временная метка, шаблоны глобусов и т. Д.
Он также совместим с более старыми версиями. Это можно найти здесь.
Вот пример:
- cleanup_files:
path_pattern: /tmp/*.log
state: absent
excludes:
- foo*
- bar*
Я хочу убедиться, что команда find только удаляет все внутри каталога и оставляет каталог нетронутым, потому что в моем случае каталог является файловой системой. Система будет выдавать ошибку при попытке удалить файловую систему, но это не очень хорошая опция. Я использую опцию оболочки, потому что это единственная рабочая опция, которую я нашел до сих пор для этого вопроса.
Что я сделал:
Отредактируйте файл hosts, добавив некоторые переменные:
[all:vars]
COGNOS_HOME=/tmp/cognos
find=/bin/find
И создайте пьесу:
- hosts: all
tasks:
- name: Ansible remove files
shell: "{{ find }} {{ COGNOS_HOME }} -xdev -mindepth 1 -delete"
Это удалит все файлы и каталоги в каталоге / файловой системе переменной COGNOS_HOME. Опция -mindepth 1 гарантирует, что текущий каталог не будет затронут.
Если вы ищете метод, который (а) идемпотентен, (б) эффективен и (в) правильно сообщает об изменениях только тогда, когда что-то изменилось, попробуйте этот. Подходит не для всех ситуаций, поскольку это зависит от:
# Idempotent method of emptying a directory
- name: Empty directories
ansible.builtin.shell: |
# Match dotfiles
shopt -s dotglob
# Make a temporary (empty) directory
tmpdir=$( mktemp -d )
# Rsync the temporary directory to the destination
rsync -a --delete $tmpdir /dir/to/empty
# Remove the temporary directory
rm -rf $tmpdir
register: empty_task
changed_when: empty_task.stdout | length > 0
Объяснение:
-
shopt -s dotglob
при использовании убедитесь, что мы также удаляем скрытые файлы (те, у которых есть.
префикс) -
tmpdir=$( mktemp -d )
дает нам пустой каталог для использования -
rsync -a --delete $tmpdir /dir/to/empty
уничтожает целевой каталог, заставляя его соответствовать новому пустому каталогу
Мы можем предположить, что ничего не изменилось, если из оболочки нет вывода.
Это очень похоже на ответ @anatolii-pedченко, который мне очень нравится. Я просто хотел версию, использующуюrsync
, благодаря своей репутации в плане эффективности работы с большими структурами каталогов.
Обратите внимание, что ни один из наших ответов не может быть зациклен как есть. Вам придется обрабатывать несколькоstdout
с (из.results
dict) с помощью цикла.
Я бы сказал, что это безопасный вариант использования модуля оболочки при условии, что вы правильно укажете целевой каталог. Хотя немного затянуто!
- name: Files to delete search
find:
paths: /home/mydata/web/
file_type: any
register: files_to_delete
- name: Deleting files to delete
file:
path: '{{ item.path }}'
state: absent
with_items: "{{ files_to_delete.files }}"
Как мы заметили, есть некоторые проблемы с регулярным выражением, удалением и копированием модуля. Таким образом, мы можем попробовать с оболочкой или командным модулем, как указано.
- name: Delete all tar files from /var/log/
become: true
command_warnings=false
command: "rm -f /var/log/*.tar”
Если вы используете Ansible> = 2.3, просто маленький шаблон для копирования и вставки из ThorSummoners (различие между файлами и директориями больше не требуется).
- name: Collect all fs items inside dir
find:
path: "{{ target_directory_path }}"
hidden: true
file_type: any
changed_when: false
register: collected_fsitems
- name: Remove all fs items inside dir
file:
path: "{{ item.path }}"
state: absent
with_items: "{{ collected_fsitems.files }}"
when: collected_fsitems.matched|int != 0
Это решение сработало для меня, и оно довольно простое, просто нужно было прочитать справочную страницу команды find в Linux.
- name: Remove contents of a directory
hosts: localhost
tasks:
- name: Find files and directories within the directory
shell:
cmd: "find path_to_your_directory -mindepth 1 -delete"
ссылка на справочную страницу find:
-minглубина уровни Не применять никаких тестов или действий на уровнях ниже уровней (неотрицательное целое число). Использование -minглубины 1 означает обработку всех файлов, кроме начальных точек.
Я следую этому файловому модулю, и лучше всего попробовать что-то из официальных документов: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html
Не все ли так просто...проверено работает..
например.
---
- hosts: localhost
vars:
cleandir: /var/lib/cloud/
tasks:
- shell: ls -a -I '.' -I '..' {{ cleandir }}
register: ls2del
ignore_errors: yes
- name: Cleanup {{ cleandir }}
file:
path: "{{ cleandir }}{{ item }}"
state: absent
with_items: "{{ ls2del.stdout_lines }}"
- name: delete old data and clean cache
file:
path: "{{ item[0] }}"
state: "{{ item[1] }}"
with_nested:
- [ "/data/server/{{ app_name }}/webapps/", "/data/server/{{ app_name }}/work/" ]
- [ "absent", "directory" ]
ignore_errors: yes
Предполагая, что вы всегда в Linux, попробуйте find
CMD.
- name: Clean everything inside {{ item }}
shell: test -d {{ item }} && find {{ item }} -path '{{ item }}/*' -prune -exec rm -rf {} \;
with_items: [/home/mydata/web]
Это должно уничтожить файлы / папки / скрытые под /home/mydata/web
Это мой пример.
- Установить репо
- Установить пакет rsyslog
- остановить rsyslog
- удалить все файлы внутри /var/log/rsyslog/
запустить rsyslog
- hosts: all tasks: - name: Install rsyslog-v8 yum repo template: src: files/rsyslog.repo dest: /etc/yum.repos.d/rsyslog.repo - name: Install rsyslog-v8 package yum: name: rsyslog state: latest - name: Stop rsyslog systemd: name: rsyslog state: stopped - name: cleann up /var/spool/rsyslog shell: /bin/rm -rf /var/spool/rsyslog/* - name: Start rsyslog systemd: name: rsyslog state: started
Ниже работал для меня,
- name: Ansible delete html directory
file:
path: /var/www/html
state: directory