list - Ansible:唯一的最短路径
问题描述
语境
我有一个要删除的文件和目录的列表。
这是从 rsync 标准输出中以单词“deleting”开头的行获得的。
rsync stdout_lines: [
"building file list ... done",
"*deleting Lab02/Ex2/Doc1.txt",
"*deleting Lab02/Ex2/",
"*deleting Lab02/Ex1/Doc1.txt",
"*deleting Lab02/Ex1/",
"*deleting Lab02/",
".d..t...... ./",
"*deleting Lab01/Ex2/Doc1.txt",
"*deleting Lab01/Ex2/",
"*deleting Lab01/Ex1/Doc2.txt",
"*deleting Lab01/Ex1/Doc1.txt",
".d..t...... Lab01/",
".d..t...... Lab01/Ex1/",
"sent 350 bytes received 191 bytes 360.67 bytes/sec",
"total size is 614 speedup is 1.13 (DRY RUN)"
]
格式化使用:
'{{ sync_return.stdout_lines | select("regex", "^[*]deleting") | map("regex_replace", "^[*]deleting", "") | map("regex_replace", " ", "") | list }}'
此列表格式的原始示例如下:
formatted list: [
"Lab02/Ex2/Doc1.txt",
"Lab02/Ex2/",
"Lab02/Ex1/Doc1.txt",
"Lab02/Ex1/",
"Lab02/",
"Lab01/Ex2/Doc1.txt",
"Lab01/Ex2/",
"Lab01/Ex1/Doc2.txt",
"Lab01/Ex1/Doc1.txt"
]
为了加快删除过程(通过减少要迭代的元素数量) - 我将列表分为 2 个子列表:
目录列表。(主列表中以“/”结尾的元素)
'{{ items_to_delete | 选择(“正则表达式”,“/$”)| 列表 }}'
文件路径列表。(包含目录的元素不会被删除)
'{{ items_to_delete | 拒绝(“匹配”,项目)| 列表 }}'
上面示例的子列表将是...
directories to delete: [
"Lab02/Ex2/",
"Lab02/Ex1/",
"Lab02/",
"Lab01/Ex2/"
]
files to delete: [
"Lab01/Ex1/Doc2.txt",
"Lab01/Ex1/Doc1.txt"
]
问题
虽然当前的解决方案有效,但它并不是最好的。梦想是有一个解决方案,其中“要删除的目录”列表仅包含可能的最高级别目录。即由于我们知道目录“Lab02/”正在被删除,“要删除的目录”将不包含“Lab02/Ex2/”或“Lab02/Ex1/”。
我相信我的目标有点类似于 os.path.commonprefix python 函数,但是必须为列表中的各种文件路径完成。
我对 Ansible 比较陌生,因此我们将不胜感激任何有关此问题的指导/帮助。
解决方案
我不会问你为什么要实现它,我会把它当作一个练习。
想法是,您可以按字母顺序对目录进行排序,然后在循环路径时,删除以上一行开头的任何目录。
您可以像这样编写过滤器(放在filter_plugins
目录中):
def common_paths(paths=[]):
sorted_paths = sorted(paths)
pfx = sorted_paths[0]
for path in sorted_paths[1:]:
if re.compile("^%s.*" % pfx).match(path):
sorted_paths.remove(path)
else:
pfx = path
return sorted_paths
class FilterModule(object):
def filters(self):
return { 'common_paths': common_paths }
然后:
- name: Filter
set_fact:
bar: "{{ foo | common_paths }}"
本地测试:
---
- hosts: localhost
tasks:
- name: Test data
set_fact:
foo:
- 'Lab01/'
- 'Lab01/Ex5/'
- 'Ex2/foo3/'
- 'Ex2/foo2/'
- 'Ex2/'
- 'Lab03/Ex5/e/'
- 'Lab02/y/z/Lab01/1/'
- 'Lab02/y/z/Lab01/3/'
- 'Lab01/Ex5/Lab02/'
- 'Lab03/Ex5/d/1'
- name: Filter
set_fact:
bar: "{{ foo | common_paths }}"
输出:
$ ansible-playbook common_paths.yml -vvv
ansible-playbook 2.10.4
PLAYBOOK: common_paths.yml *********************************************************************************
1 plays in common_paths.yml
PLAY [localhost] *********************************************************************************
TASK [Gathering Facts] *********************************************************************************
ok: [localhost]
TASK [Test data] ********************************************************************************* task path: /home/guido/Development/git/ansible-local/common_paths.yml:5
ok: [localhost] => {
"ansible_facts": {
"foo": [
"Lab01/",
"Lab01/Ex5/",
"Ex2/foo3/",
"Ex2/foo2/",
"Ex2/",
"Lab03/Ex5/e/",
"Lab02/y/z/Lab01/1/",
"Lab02/y/z/Lab01/3/",
"Lab01/Ex5/Lab02/",
"Lab03/Ex5/d/1/"
]
},
"changed": false
}
TASK [Filter] *********************************************************************************
task path: /home/guido/Development/git/ansible-local/common_paths.yml:19
ok: [localhost] => {
"ansible_facts": {
"bar": [
"Ex2/",
"Lab01/",
"Lab02/y/z/Lab01/1/",
"Lab02/y/z/Lab01/3/",
"Lab03/Ex5/d/1/",
"Lab03/Ex5/e/"
]
},
"changed": false
}
PLAY RECAP *********************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
推荐阅读
- python-3.x - 从 python 运行 ./run.ps1 脚本
- python - 如何将边缘类型分类?特别是如何根据 G.edges() 重新索引 df?
- apache-kafka - 卡夫卡连接。如何设置批处理大小,它指定何时关闭零件文件并开始新文件
- spring-boot - 我无法在 ibm websphere 中运行 Spring Boot 战争文件
- javascript - 如何将 Javascript 中两个选择的值与使用 javascript 的动态内容进行比较
- java - 有没有办法在模拟器背景中不运行谷歌地图应用程序的情况下不断更新纬度经度
- html - 页面打开时出现 Angular TypeError
- android - 如何在 Android 中始终为 TextInputLayout EditText 禁用软键盘?
- javascript - 确定阶乘函数的尾随零的数量 (javascript)
- node.js - 如何让 Bulljs 与 Elasticache Cluster 一起工作?