Ansible循环中json_query结果追加闭合方括号致scp失败
Ansible中json_query返回列表引发scp执行失败的解决办法
问题现象
循环迭代时,json_query提取的路径列表被直接插入scp命令,导致命令中出现方括号[],拼接路径后变成['/path/to/dir1']/data,最终scp因找不到路径/path/to/dir1]/data执行失败。
错误输出
failed: [node1] (item={'source_path': ['/path/to/dir1/data/snapshot.20230414003127854', '/path/to/dir2/data/snapshot.20230414003128467', '/path/to/dir3/data/snapshot.20230414003129100', '/path/to/dir4/data/snapshot.20230414003129744'], 'target_path': ['/path/to/dir1', '/path/to/dir2', '/path/to/dir3', '/path/to/dir4']}) => { "ansible_loop_var": "item", "changed": true, "cmd": "scp -r -o StrictHostKeyChecking=no ['/path/to/dir1/data/snapshot.20230414003127854', '/path/to/dir2/data/snapshot.20230414003128467', '/path/to/dir3/data/snapshot.20230414003129100', '/path/to/dir4/data/snapshot.20230414003129744'] user@target_node:['/path/to/dir1', '/path/to/dir2', '/path/to/dir3', '/path/to/dir4']/data", "delta": "0:00:00.011310", "end": "2023-04-13 19:31:43.326500", "invocation": { "module_args": { "_raw_params": "scp -r -o StrictHostKeyChecking=no ['/path/to/dir1/data/snapshot.20230414003127854', '/path/to/dir2/data/snapshot.20230414003128467', '/path/to/dir3/data/snapshot.20230414003129100', '/path/to/dir4/data/snapshot.20230414003129744'] user@target_node:['/path/to/dir1', '/path/to/dir2', '/path/to/dir3', '/path/to/dir4']/data", "_uses_shell": true, "argv": null, "chdir": null, "creates": null, "executable": null, "removes": null, "stdin": null, "stdin_add_newline": true, "strip_empty_ends": true, "warn": true } }, "item": { "source_path": [ "/path/to/dir1/data/snapshot.20230414003127854", "/path/to/dir2//data/snapshot.20230414003128467", "/path/to/dir3/data/snapshot.20230414003129100", "/path/to/dir4/data/snapshot.20230414003129744" ], "target_path": [ "/path/to/dir1", "/path/to/dir2", "/path/to/dir3", "/path/to/dir4" ] }, "msg": "non-zero return code", "rc": 1, "start": "2023-04-13 19:31:43.315190", "stderr": "/path/to/dir1]/data: No such file or directory", "stderr_lines": [ "/path/to/dir1]/data: No such file or directory" ], "stdout": "", "stdout_lines": [] }
原执行代码
- name: copy files shell: "scp -r -o StrictHostKeyChecking=no {{ item.source_path }} user@{{ target_primary_node }}:{{ item.target_path }}/data" with_items: - { source_path: "{{ source_path.results|json_query('[].files[].path') }}", target_path: "{{ dest_path.results|json_query('[].files[].path') }}" }
问题原因
json_query('[].files[].path')返回列表类型,直接在模板中引用时,Ansible会将列表渲染为带方括号和引号的字符串,导致scp把方括号当成路径的一部分。- 当前
with_items仅定义一个包含两个列表的元素,循环仅执行一次,尝试一次性传递所有路径给scp,不符合scp多源多目标一一对应的参数格式要求。
解决方案
方法1:用zip过滤器配对路径后循环
实现源路径与目标路径一一对应传输:
- name: copy files shell: "scp -r -o StrictHostKeyChecking=no {{ item.0 }} user@{{ target_primary_node }}:{{ item.1 }}/data" loop: "{{ source_path.results|json_query('[].files[].path') | zip(dest_path.results|json_query('[].files[].path')) | list }}"
方法2:先注册配对变量再循环
若需要更清晰的结构,可先将配对结果注册为变量:
- name: prepare path pairs set_fact: path_pairs: "{{ source_path.results|json_query('[].files[].path') | zip(dest_path.results|json_query('[].files[].path')) | list }}" - name: copy files shell: "scp -r -o StrictHostKeyChecking=no {{ item.0 }} user@{{ target_primary_node }}:{{ item.1 }}/data" loop: "{{ path_pairs }}"
特殊场景:一次性传输所有文件到单目标
若只需将所有源文件传到同一个目标目录,可用join(' ')把列表转为空格分隔的字符串:
- name: copy all files to single target shell: "scp -r -o StrictHostKeyChecking=no {{ source_paths | join(' ') }} user@{{ target_primary_node }}:/path/to/target_dir/data" vars: source_paths: "{{ source_path.results|json_query('[].files[].path') }}"
内容的提问来源于stack exchange,提问作者reddy0969
相关产品推荐
相关产品推荐

