Ansible递归删除匹配正则表达式文件失败问题求助
我来帮你分析下两种方法失败的原因,再给出可行的解决方案:
为什么你的方法失败了?
1. Shell模块的问题
你用ls -R | grep ... | xargs rm的方式有个致命问题:ls -R输出的子目录文件不带相对路径。比如subdir1/fileX_001.dat会被显示成fileX_001.dat,当你在dir1目录下执行rm时,它只会在当前目录(dir1)找这个文件,而实际文件在subdir1里,自然找不到。另外ls -R的输出还包含目录名行(比如subdir1:),可能会被grep误匹配,进一步导致错误。
2. Find模块的问题
Ansible的find模块默认使用POSIX扩展正则,而你写的(?!2)是PCRE(Perl兼容正则)独有的负向前瞻语法,POSIX正则不支持这个特性,所以你的正则表达式无法被正确解析,自然匹配不到任何文件。
可行的解决方案
方案一:用Shell模块调用find命令(最直接)
直接用系统的find命令来递归查找并删除文件,它能正确处理文件路径,还支持PCRE正则(如果系统的find支持的话):
- name: 删除匹配的文件(先测试再删除) shell: find . -type f -regextype posix-extended -regex '.*?_(?!2)[0-9]{2,}\.(dat|DAT)' -print args: chdir: 'dir1'
确认输出的文件都是你想删除的之后,把-print换成-delete即可直接删除:
- name: 正式删除匹配的文件 shell: find . -type f -regextype posix-extended -regex '.*?_(?!2)[0-9]{2,}\.(dat|DAT)' -delete args: chdir: 'dir1'
注意:如果是BSD系统(比如macOS)的
find,可能需要把-regextype posix-extended换成-E参数来启用扩展正则。
方案二:修复Find模块的正则表达式(纯Ansible方式)
把PCRE的负向前瞻转换成POSIX兼容的写法,这样find模块就能识别了。你的需求是“下划线后非2开头,后跟至少两位数字”,对应的POSIX正则可以写成:.*_([^2][0-9]+)\.(dat|DAT)。
完整的Playbook代码:
- name: 定义POSIX兼容的正则表达式 set_fact: file_regex: '.*_([^2][0-9]+)\.(dat|DAT)' - name: 查找所有匹配的文件 find: paths: "dir1" patterns: "{{ file_regex }}" use_regex: yes recurse: yes file_type: file # 只找文件,排除目录 register: found_files - name: 删除找到的文件 file: path: '{{ item.path }}' state: absent with_items: '{{ found_files.files }}'
这个正则的逻辑是:
.*_:匹配任意字符直到下划线[^2][0-9]+:第一位字符不是2,后面跟至少一个数字(确保整体是至少两位数字,且不以2开头)\.(dat|DAT):匹配.dat或.DAT结尾
方案三:用Command模块调用find(兼容所有场景)
如果不想纠结正则兼容性,直接用command模块调用系统find命令获取文件路径,再用file模块删除:
- name: 获取所有匹配文件的路径 command: find dir1 -type f -regextype posix-extended -regex '.*?_(?!2)[0-9]{2,}\.(dat|DAT)' register: found_files - name: 删除匹配的文件 file: path: '{{ item }}' state: absent with_items: '{{ found_files.stdout_lines }}'
同样,建议先执行第一步查看输出是否正确,再执行删除步骤。
内容的提问来源于stack exchange,提问作者lubik

