Ansible:用一个命令将多个文件从多个源复制到多个目标
我正在尝试将一些配置文件从/tmp复制到/opt。 首先,我递归搜索/tmp和/opt目录中的文件,并将其分别存储在变量tmp_file_path和code_file_path中,该变量有一个属性files.path,我需要在源和目标中使用该属性进行复制Ansible:用一个命令将多个文件从多个源复制到多个目标,ansible,Ansible,我正在尝试将一些配置文件从/tmp复制到/opt。 首先,我递归搜索/tmp和/opt目录中的文件,并将其分别存储在变量tmp_file_path和code_file_path中,该变量有一个属性files.path,我需要在源和目标中使用该属性进行复制 - name: Find files in tmp find: paths: /tmp/ file_type: file recurse: yes patterns: - file1
- name: Find files in tmp
find:
paths: /tmp/
file_type: file
recurse: yes
patterns:
- file1
- file2
- file3
register: tmp_file_path
- debug:
var: tmp_file_path
- name: Find files in code
find:
paths: /opt/
file_type: file
recurse: yes
patterns:
- file1
- file2
- file3
register: code_file_path
- debug:
var: code_file_path
这里的源文件路径可以是/tmp/folder1/file1、/tmp/folder2/file2、/tmp/folder13/file3。
目的地可以是/opt/folderA/file1、/opt/folderB/file3、/opt/folderC/file3
到目前为止,我已设法将任务写如下
- name: Copy files from tmp to code directory
copy:
src: "{{item.path}}"
dest: "{{item.path}}"
remote_src: yes
with_items:
- { "{{ tmp_file_path.files }}", "{{ code_file_path.files }}" }
复制必须在单个命令中完成,这样我就不会最终硬编码源和目标的路径。谁能帮我实现这个目标
下面是一段用于将文件从代码文件路径递归复制到/tmp的代码
- name: Copy files from code directory to tmp
copy:
src: "{{item.path}}"
dest: /tmp/
remote_src: yes
with_items: "{{code_file_path.files}}"
试试这个
- name: Copy files from tmp to code directory
copy:
src: "{{ item.0 }}"
dest: "{{ item.1 }}"
remote_src: yes
with_together:
- "{{ tmp_file_path.files|map(attribute='path')|list|sort }}"
- "{{ code_file_path.files|map(attribute='path')|list|sort }}"
首先尝试调试
- debug:
msg:
- "src: {{ item.0 }}"
- "dest: {{ item.1 }}"
with_together:
- "{{ tmp_file_path.files|map(attribute='path')|list|sort }}"
- "{{ code_file_path.files|map(attribute='path')|list|sort }}"
首先测试是否正常可能很有用
- debug:
msg: The numbers of files do not match
when: tmp_file_path.files|map(attribute='path')|list|length !=
code_file_path.files|map(attribute='path')|list|length
问:“这没有按预期工作,因为我在code_file_path中搜索的文件有多个子目录。它在code_file_path.files返回的整个文件路径上排序,而不仅仅是文件名。” 答:创建一个包含路径和名称的列表。然后按名称对列表进行排序。比如说
- set_fact:
code_files: "{{ code_files|default([]) +
[{'path': item, 'name': item|basename}] }}"
loop: "{{ code_file_path.files|map(attribute='path')|list }}"
- debug:
msg:
- "src: {{ item.0 }}"
- "dest: {{ item.1.path }}"
with_together:
- "{{ tmp_file_path.files|map(attribute='path')|list|sort }}"
- "{{ code_files|sort(attribute='name') }}"
范例
shell> tree tmp
tmp
├── file1
├── file2
└── file3
shell> tree opt
opt
├── bar
│ └── file2
├── baz
│ └── file3
└── foo
└── file1
下面的任务
- set_fact:
code_files: "{{ code_files|default([]) +
[{'path': item, 'name': item|basename}] }}"
loop: "{{ code_file_path.files|map(attribute='path')|list }}"
- debug:
var: code_files|sort(attribute='name')
- debug:
msg:
- "src: {{ item.0 }}"
- "dest: {{ item.1.path }}"
with_together:
- "{{ tmp_file_path.files|map(attribute='path')|list|sort }}"
- "{{ code_files|sort(attribute='name') }}"
给予
您可以通过以下条件实现这一点:每个文件名都是唯一的,如果/opt目录中的列表中有两个文件具有相同的名称,那么它们的内容应该是相同的 如果是这种情况,则可以使用with_嵌套循环,并在打开文件名时使用conditional 例如:
- name: Copy files from tmp to code directory
copy:
src: "{{ item.0 }}"
dest: "{{ item.1 }}"
remote_src: yes
when:
- item.0|basename == item.1|basename
with_nested:
- "{{ tmp_file_path.files|map(attribute='path')|list }}"
- "{{ code_file_path.files|map(attribute='path')|list }}"
这个解决方案唯一的“问题”是你会运行循环很多次
您可能还希望将循环syntax与_syntax一起使用,并使用一些循环控制来选择打印的内容:
如果加载了jinja.ext.do扩展名(在ansible.cfg:
jinja2_extensions=jinja2.ext.do
),则可以使用路径构建dict:
- name: Make a dict
set_fact:
files_dict: |
{%- set out_dict = dict() -%}
{%- for tmp_file in tmp_file_path.files|map(attribute='path')|list -%}
{%- do out_dict.update({tmp_file|basename: {'tmp': tmp_file}}) -%}
{%- endfor -%}
{%- for opt_file in code_file_path.files|map(attribute='path')|list -%}
{%- do out_dict[opt_file|basename].update({'opt': opt_file}) -%}
{%- endfor -%}
{{ out_dict }}
- name: Copy from dict
copy:
src: "{{ item.value.tmp }}"
dest: "{{ item.value.opt }}"
remote_src: yes
with_dict: "{{ files_dict }}"
@VladimirBotka好的,让我更正一下,我需要将/opt中的文件名file1、file2和file3替换为/opt中的文件/tmp@VladimirBotka是的,你是对的,文件名完全相同。在这里,我可以执行命令来替换文件,但我需要遍历已注册的变量tmp_file_path和code_file_path谢谢您的回答。这没有像预期的那样工作,因为我正在代码文件路径中搜索的文件有多个子目录。这导致“排序”无法按预期运行。示例如下(item=['/tmp/test/file1'、'/opt/Application/code/server/file1'])(item=['/tmp/test/file2'、'/opt/Application/app/server/file3'])(item=['/tmp/test/file3'、'/opt/Application/app/server/file2']),因此,它基本上是按照code\file\u path.files返回的整个文件路径排序,而不仅仅是文件名。是否有一种方法可以修剪文件名并基于此进行排序?需要一个选项来修剪文件名,排序,然后附加整个路径,最后复制或移动它。这对我来说仍然没有达到预期效果。这是将变量设置为无。谢谢你的帮助。我能够理解并在其他地方使用这段代码。这个更新的答案符合我的确切要求。如果可能的话,你可以看看查找模块的问题吗这是可行的,但是正如你提到的,有多个循环的开销
- name: Make a dict
set_fact:
files_dict: |
{%- set out_dict = dict() -%}
{%- for tmp_file in tmp_file_path.files|map(attribute='path')|list -%}
{%- do out_dict.update({tmp_file|basename: {'tmp': tmp_file}}) -%}
{%- endfor -%}
{%- for opt_file in code_file_path.files|map(attribute='path')|list -%}
{%- do out_dict[opt_file|basename].update({'opt': opt_file}) -%}
{%- endfor -%}
{{ out_dict }}
- name: Copy from dict
copy:
src: "{{ item.value.tmp }}"
dest: "{{ item.value.opt }}"
remote_src: yes
with_dict: "{{ files_dict }}"