I have the following list of dictionaries:
"errorlist": [
{
"error": "Not found",
"path": "/tmp/working/directory1/file1"
},
{
"error": "Not found",
"path": "/tmp/working/directory2/file1"
},
{
"error": "Not found",
"path": "/tmp/working/directory1/file2"
},
{
"error": "Not found",
"path": "/tmp/working/directory2/file2"
}
]
I'd like to remove the "/tmp/working/" part of the path values, i.e. convert the absolute paths to relative ones.
I've been through similar questions while searching online but haven't found a solution. It should be rather simple but I can't wrap my head around it.
The expected result should be either the original list with updated values or a new list with the same structure.
Filter the basenames and create a list of dictionaries
paths: "{{ errorlist | map(attribute='path') | map('basename') |
map('community.general.dict_kv', 'path') }}"
gives
paths:
- {path: file1}
- {path: file1}
- {path: file2}
- {path: file2}
zip the lists and combine the items
result: "{{ errorlist | zip(paths) | map('combine') }}"
gives
result:
- {error: Not found, path: file1}
- {error: Not found, path: file1}
- {error: Not found, path: file2}
- {error: Not found, path: file2}
Fit the pipes to your needs.
- hosts: localhost
vars:
errorlist:
- {error: Not found, path: /tmp/working/directory1/file1}
- {error: Not found, path: /tmp/working/directory2/file1}
- {error: Not found, path: /tmp/working/directory1/file2}
- {error: Not found, path: /tmp/working/directory2/file2}
paths: "{{ errorlist | map(attribute='path') | map('basename') |
map('community.general.dict_kv', 'path') }}"
result: "{{ errorlist | zip(paths) | map('combine') }}"
tasks:
- debug:
var: paths | to_yaml
- debug:
var: result | to_yaml
paths: "{{ errorlist | map(attribute='path') |
map('regex_replace', '/tmp/working/(.*)', '\\1') |
map('community.general.dict_kv', 'path') }}"
gives
paths:
- {path: directory1/file1}
- {path: directory2/file1}
- {path: directory1/file2}
- {path: directory2/file2}
This will result in
result:
- {error: Not found, path: directory1/file1}
- {error: Not found, path: directory2/file1}
- {error: Not found, path: directory1/file2}
- {error: Not found, path: directory2/file2}
Q: "How can I achieve the same result without community.general.dict_kv?"
A: Use json_query. The below declaration gives the same result
paths: "{{ errorlist | map(attribute='path') |
map('regex_replace', '/tmp/working/(.*)', '\\1') |
json_query('[].{path: @}') }}"
In Ansible 2.9 and lower try to add the filter list
paths: "{{ errorlist | map(attribute='path') | list |
map('regex_replace', '/tmp/working/(.*)', '\\1') | list |
json_query('[].{path: @}') | list }}"
Debugging
Decompose the pipe
path1: "{{ errorlist | map(attribute='path') }}"
path2: "{{ errorlist | map(attribute='path') |
map('regex_replace', '/tmp/working/(.*)', '\\1') }}"
path3: "{{ errorlist | map(attribute='path') |
map('regex_replace', '/tmp/working/(.*)', '\\1') |
json_query('[].{path: @}') }}"
and display the types of intermediary results
- debug:
msg: "{{ path1 | type_debug }}"
- debug:
msg: "{{ path2 | type_debug }}"
- debug:
msg: "{{ path3 | type_debug }}"