Ansible:独特的最短路径
Ansible: Unique Shortest Paths
上下文
我有一个要删除的文件和目录列表。
这是从 rsync 标准输出中以单词“删除”开头的行获得的。
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 | select("正则表达式", "/$") |列表}}'
文件路径列表。 (包含目录的元素不会被删除)
'{{ 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 比较陌生,所以如果 guidance/help 有任何关于此事的意见,我们将不胜感激。
我不会问你为什么要实现它,我会把它当作练习。
想法是,您可以按字母顺序对目录进行排序,然后在循环路径时,删除以上一行开头的所有路径。
你可以这样写你的过滤器(放在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
上下文
我有一个要删除的文件和目录列表。
这是从 rsync 标准输出中以单词“删除”开头的行获得的。
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 | select("正则表达式", "/$") |列表}}'
文件路径列表。 (包含目录的元素不会被删除)
'{{ 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 比较陌生,所以如果 guidance/help 有任何关于此事的意见,我们将不胜感激。
我不会问你为什么要实现它,我会把它当作练习。
想法是,您可以按字母顺序对目录进行排序,然后在循环路径时,删除以上一行开头的所有路径。
你可以这样写你的过滤器(放在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