Ansible:如何删除目录中的文件和文件夹?


152

以下代码仅删除它从Web目录中获取的第一个文件。我想删除Web目录中的所有文件和文件夹,并保留Web目录。我怎样才能做到这一点?

  - name: remove web dir contents
     file: path='/home/mydata/web/{{ item }}' state=absent
     with_fileglob:
       - /home/mydata/web/*

注意:我已经尝试rm -rf使用命令和shell,但是它们不起作用。也许我错误地使用了它们。

朝正确方向的任何帮助将不胜感激。

我正在使用ansible 2.1.0.0


看起来像个错误。
ceving

Answers:


133

下面的代码将删除全部内容 artifact_path

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

注意:这也会删除目录。


3
不需要引号。这只是我的工作代码。artifact_path类似于/ app / my_app / work /
Mohan Kumar P

83
OP(和我自己)想要一个解决方案,该解决方案将删除文件夹的内容,而不是文件夹本身。此解决方案删除内容和文件夹本身。
随机

19
这是如何获得支持的?这也会删除目录。
deppfx

17
有没有人让上面的代码在artifact_path为null的情况下失败?感觉它可能会受到rm -rf /历史上那些伟大时刻的影响
ted-k42 '17

2
@ ted-k42为了安全起见,我会这样做:when: artifact_path is defined and artifact_path != ""
bmaupin

69

使用外壳模块(也是幂等的):

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

如果您不关心创建日期和所有者/权限,这是最干净的解决方案:

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

7
可行,但没有删除以开头的文件。像.htaccess一样
阿巴斯(Abbas)

壳牌也为我工作。完全相同的任务,但换shellcommand和它的作品
SomethingOn

4
通配符不适用于命令,因为它们需要外壳进行扩展
JamesP

1
请注意,除非您在创建时明确设置,否则这可能会更改您的权限/所有者。
NeverEndingQueue

使用shell时,您将得到一个警告,提示您使用state = absent而不是rm的文件模块。为了避免这种情况,只需添加 args:警告:false
Rodrigo

59

删除目录(基本上是https://stackoverflow.com/a/38201611/1695680的副本),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
      }}

5
第一个任务是我见过的最优雅的解决方案。注意:评论其他地方,有一个长期运行的功能要求增加state=empty
威廉·特瑞尔

24

我真的不喜欢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/


仍然是问题的最佳解决方案!
Vsegar

18

试试下面的命令,它应该工作

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

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

3
您错过了用{{,}}正确逃脱最后一行以获得with_items: "{{ contents.stdout_lines }}"
Valerio Crini

使用ls'输出获取文件名是危险的,因为它不能正确打印带有特殊字符(例如换行符)的文件名。
bfontaine

5

根据所有评论和建议,创建了一个全面的,经过全面修复的安全实施方案:

# 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

我认为您缺少registerfor plugin_dir_deleted,对吧?
鲍勃·沃克

感谢您指出了这一点。我从其中一本剧本中摘录了这段代码,并使其在命名方面更加通用,但忘记替换两个变量名
Markus

1
好东西,但是我认为最后一个任务的状态需要设置为“目录”而不是“当前”。
安德鲁·阿莱尔

1
您应该使用统计结果来保留权限:pw_name的所有者,gr_name的组和mode的模式。
DylanYoung '18

尝试过, owner: dir_to_delete.stat.pw_name, group: dir_to_delete.stat.gr_name mode: dir_to_delete.stat.mode但使用我当前的Ansible版本对我却失败了:(
马库斯

3

使用文件glob也可以。您发布的代码中存在语法错误。我已经修改并测试了它应该可以工作。

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

7
with_fileglob仅在本地计算机上工作,而不在远程计算机上工作;是不是真的
Stepan Vavra

正确。with_fileglob仅适用于本地
Mittal

另外,这不会删除目录,只会删除文件。
vikas027

2

虽然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 }}"

但是请注意,通过同步,无论如何,您都应该能够正确同步文件(带有删除)。


2

那就是我想出的:

- 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_typeany,因此我们不会错过嵌套的目录和链接
  • hiddenyes,因此我们不会跳过隐藏文件
  • 另外,请勿将其设置recurseyes,因为这不仅不必要,而且会增加执行时间。

然后,我们通过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如果需要,您也可以添加。


1

对此存在一个未解决的问题

目前,该解决方案适合我:在本地创建一个空文件夹,并将其与远程文件夹同步。

这是一个示例剧本:

- 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

1

我已经编写了一个自定义ansible模块,以基于多个过滤器(例如年龄,时间戳记,全局模式等)来清理文件。

它也与旧版本兼容。可以在这里找到。

这是一个例子:

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

0

我想确保find命令仅删除目录内的所有内容,并保持目录不变,因为在我的情况下,目录是文件系统。尝试删除文件系统时,系统将生成错误,但这不是一个好的选择。我使用shell选项,因为这是我到目前为止针对该问题找到的唯一可行的选项。

我做了什么:

编辑主机文件以放入一些变量:

[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”选项可确保不会触摸当前目录。


0

如果您使用的是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

-1

假设您一直在Linux中,请尝试使用findcmd。

- 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


1
可能可行,但是使用shell模块应该永远是最后的选择。
克里斯(Chris)

-1
先删除对应的目录,然后在创建该目录,使用的是嵌套循环
  - 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

-4

这是我的例子。

  1. 安装仓库
  2. 安装rsyslog软件包
  3. 停止rsyslog
  4. 删除/ var / log / rsyslog /中的所有文件
  5. 启动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
    

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.