【问题标题】:Copy multiple files with Ansible使用 Ansible 复制多个文件
【发布时间】:2016-08-10 08:47:43
【问题描述】:

如何在任务中通过 Ansible 将多个文件复制到远程节点?

我试图在我的任务中复制复制模块行来定义文件,但它只复制第一个文件。

【问题讨论】:

    标签: ansible


    【解决方案1】:

    您可以为此使用with_fileglob 循环:

    - copy:
        src: "{{ item }}"
        dest: /etc/fooapp/
        owner: root
        mode: 600
      with_fileglob:
        - /playbooks/files/fooapp/*
    

    【讨论】:

    • 如果我将所有文件都放在同一个根目录中以复制到远程机器中,这种方法可以帮助我,如果在不同的目录中有一些文件呢?例如,我想从 3 个不同的目录复制 3 个文件
    • 嘿,我正在尝试从我的/roles/db/files 中移动所有文件,但我无法使用这种方法。我试过with_fileglob: - /roles/db/file/*,但路径不好
    • 这种方法的最大缺点是它会使目录结构变平。
    【解决方案2】:
    - name: Your copy task
      copy: src={{ item.src }} dest={{ item.dest }}
      with_items:
        - { src: 'containerizers', dest: '/etc/mesos/containerizers' }
        - { src: 'another_file', dest: '/etc/somewhere' }
        - { src: 'dynamic', dest: '{{ var_path }}' }
      # more files here
    

    【讨论】:

    • 是否可以将此解决方案与dest 设置为变量? { src: 'containerizers', dest: {{ containerizers }} }.
    • @Gesias,是的。其实两边都可以是变量:{ src: '{{ source.var }}', dest: '{{ dest.var }}' }
    【解决方案3】:

    从 Ansible 2.5 开始,应该使用 with_* 构造 are not recommendedloop 语法。一个简单实用的例子:

    - name: Copy CA files
      copy:
        src: '{{item}}'
        dest: '/etc/pki/ca-trust/source/anchors'
        owner: root
        group: root
        mode: 0644
      loop:
        - symantec-private.crt
        - verisignclass3g2.crt
    
    

    【讨论】:

    • page you linked 上明确表示with_* 已被弃用:“我们尚未弃用with_<lookup> - 该语法仍然适用于可预见的未来。” (截至 2021 年 11 月)他们只推荐它。
    • 感谢您发现这一点 - 该通知之前不存在,它是在 2019 年末的某个时候添加的。将相应地修改答案。
    【解决方案4】:

    你可以使用 with_together 来达到这个目的:

    - name: Copy multiple files to multiple directories
      copy: src={{ item.0 }} dest={{ item.1 }}
      with_together:
        - [ 'file1', 'file2', 'file3' ]
        - [ '/dir1/', '/dir2/', '/dir3/' ]
    

    【讨论】:

    • 虽然它有效,但这在语义上并不干净 - 有更清洁的选项。
    【解决方案5】:

    如果您需要多个位置,则需要多个任务。一个复制任务只能从一个位置(包括多个文件)复制到节点上的另一个位置。

    - copy: src=/file1 dest=/destination/file1
    - copy: src=/file2 dest=/destination/file2
    
    # copy each file over that matches the given pattern
    - copy: src={{ item }} dest=/destination/
      with_fileglob:
        - /files/*
    

    【讨论】:

    • - 名称:复制文件1 复制:src=/file1 dest=/destination/file1 - 名称:复制文件2 复制:src=/file2 dest=/destination/file2
    • 视情况而定。更简单且可能更简洁,但可以使用更复杂的数据结构来完成,例如带有源数据和目标数据的匿名字典列表,用_items 循环。在任何语言中都是一样的——你必须做出判断。在某些情况下,委托函数比一长串复制/粘贴的 if 语句更有效且可维护。我是那种宁愿保持简洁的结构良好的代码而不是冗长乏味的几乎相同指令列表的怪胎,但我不认为每个人都同意。做你可以维护的事情。
    【解决方案6】:
    - hosts: lnx
      tasks:
        - find: paths="/appl/scripts/inq" recurse=yes patterns="inq.Linux*"
          register: file_to_copy
        - copy: src={{ item.path }} dest=/usr/local/sbin/
          owner: root
          mode: 0775
          with_items: "{{ files_to_copy.files }}"
    

    【讨论】:

    • 请注意find 模块仅适用于 ansible 2.x,但不适用于 ansible 1.x
    • 我已经修复了您的答案,因为您在返回值中提到了stdout_lines,但不适用于find 模块。它只有filesexaminedmatched 作为返回值。希望对其他人有所帮助
    • 有人能够将文件复制到远程节点吗? find 似乎只查看远程系统,不允许从管理节点获取任何东西。这些答案,使用with_fileglob,似乎更合适:stackoverflow.com/a/42290160/272387stackoverflow.com/a/36720342/272387
    【解决方案7】:
    - name: find inq.Linux*
      find:  paths="/appl/scripts/inq" recurse=yes patterns="inq.Linux*"
      register: find_files
    
    
    - name: set fact
      set_fact:
        all_files:
          - "{{ find_files.files | map(attribute='path') | list }}"
      when: find_files > 0
    
    
    - name: copy files
      copy:
        src: "{{ item }}"
        dest: /destination/
      with_items: "{{ all_files }}"
      when: find_files > 0
    

    【讨论】:

    • 一个好的答案不仅包含代码,还包含一些解释或文档参考。
    • find、set_fact 和 copy 模块在 ansible 文档中都有解释。阅读有关过滤器的信息,如果您想了解有关本节的更多信息,也可以在 ansible 文档中了解 (- "{{ find_files.files | map(attribute'path') | list }}")
    • Copy 假定本地源,所以为了使这个例子自洽,要么 find 选项需要在 localhost 上运行一次,否则最终的复制操作需要指定一个远程 src。这种方法的好处是它使文件列表可用于其他目的(例如,如果副本只是临时的,则稍后删除)。
    【解决方案8】:

    或者你可以使用 with_items:

    - copy:
        src: "{{ item }}"
        dest: /etc/fooapp/
        owner: root
        mode: 600
      with_items:
        - dest_dir
    

    【讨论】:

      【解决方案9】:

      copy 模块是复制许多文件和/或目录结构的错误工具,请使用synchronize 模块,而不是使用rsync 作为后端。请注意,它需要在控制器和目标主机上安装rsync。真的很强大,查看ansible documentation

      示例 - 将文件从控制器的build 目录(带有子目录)复制到目标主机上的/var/www/html 目录:

      synchronize:
        src: ./my-static-web-page/build/
        dest: /var/www/html
        rsync_opts:
          - "--chmod=D2755,F644" # copy from windows - force permissions
      

      【讨论】:

        【解决方案10】:

        您可以使用目录列表遍历变量:

        - name: Copy files from several directories
          copy:
            src: "{{ item }}"
            dest: "/etc/fooapp/"
            owner: root
            mode: "0600"
          loop: "{{ files }}"
          vars:
            files:
              - "dir1/"
              - "dir2/"
        

        【讨论】:

          【解决方案11】:

          使用以下源代码在您的客户端计算机上复制多个文件。


           - name: Copy data to the client machine
             hosts: hostname
             become_method: sudo
             become_user: root
             become: true
             tasks: 
               # Copy twice as sometimes files get skipped (mostly only one file skipped from a folder if the folder does not exist)
               - name: Copy UFO-Server 
                 copy:
                   src: "source files path"
                   dest: "destination file path"
                   owner: root
                   group: root
                   mode: 0644
                   backup: yes
                 ignore_errors: true
          

          注意:

          如果你使用变量传递多个路径,那么

          src: "/root/{{ item }}"

          如果您通过对不同项目使用变量来传递路径,那么

          src: "/root/{{ item.source_path }}"

          【讨论】:

            【解决方案12】:

            这里是复制文件的通用解决方案:

               ...
                - name: Find files you want to move
                  ansible.builtin.find:
                    paths: /path/to/files/
                    file_type: file
                    excludes: "*.txt" # Whatever pattern you want to exclude
                  register: files_output
            
                - name: Copy the files
                  ansible.builtin.copy:
                    src: "{{ item.path }}"
                    dest: /destination/directory/
                  loop: "{{ files_output.files }}"
               ...
            

            这比使用with_fileglob 更强大,因为您可以使用正则表达式进行匹配。下面是这个游戏的实际效果:

            $ ls /path/to/files
            demo.yaml  test.sh  ignore.txt
            
            $ ls /destination/directory
            file.h
            
            $ ansible-playbook playbook.yaml
            ...[some output]...
            
            $ ls /destination/directory
            file.h demo.yaml test.sh
            

            从上面的例子可以看出,ignore.txt 没有被复制到目标目录,因为 playbook 中的 excludes 正则表达式。仅使用with_fileglob 无法忽略此类文件。

            此外,您可以相对轻松地从多个目录移动文件:

               ...
                - name: Find files you want to move
                  ansible.builtin.find:
                    paths: /path/to/files/
                    # ... the rest of the task
                  register: list1
            
                - name: Find more files you want to move
                  ansible.builtin.find:
                    paths: /different/path/
                    # ... the rest of the task
                  register: list2
            
                - name: Copy the files
                  ansible.builtin.copy:
                    src: "{{ item.path }}"
                    dest: /destination/directory/
                  loop: "{{ list1.files + list2.files }}"
               ...
            

            【讨论】:

            • 请添加更多细节,并添加一些示例。
            • @sorosh_sabz 应要求 ?
            【解决方案13】:

            这是一个示例 Ansible 脚本,用于在远程主机上复制多个文件

            • 名称:在远程主机上复制多个文件

            ansible.windows.win_copy:

                           src: "{{ SrcPath }}/{{ item}}" #Remeber to use {{item}} as a postfix to source path
            
                           dest: "{{destPath}}"
            
                           remote_src: yes [if Source Path available on remote Host]
            
                           with_items:
                             - abc.txt
                             - abc.properties
            

            【讨论】:

              【解决方案14】:

              • 主机:测试 收集事实:假 变成:真 变量: 路径:'/home/ansibm/playbooks' 远程路径:'/home/{{ansible_ssh_user}}' 目录:'yml_files' 任务:
                • name: "为备份文件创建目录" 文件: 路径:'{{ remote_path }}/{{ dir }}' 状态:目录 所有者:'{{ansible_ssh_user}}' 组:'{{ansible_ssh_user}}' 模式:0700
                • 名称:“复制 yml 文件” 复制: 源代码:'{{item}}' dest: '{{ remote_path }}/{{ dir }}' 所有者:'{{ansible_ssh_user}}' 组:'{{ansible_ssh_user}}' 模式:0644 环形: - '{{ 路径 }}/ab.html' - '{{ 路径 }}/cp.yml'

              【讨论】:

              • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
              【解决方案15】:

              使用 Ansible 将文件从多个目录复制到多个目录

              我发现guenhter 的答案很有帮助,但还需要更改远程文件的模式。我没有足够的声誉将此作为评论,这将是一个更合适的地方。在示例中,我将两个目录中的两个文件复制到 /tmp 和 /tmp/bin 中,我首先创建并修改远程文件模式。

              - name: cpldupd
                hosts: test
                remote_user: root
                become: true
                vars:
                  - rpth: /tmp
                tasks:
                  - name: Create '{{rpth}}/bin'
                    file:
                      path: '{{rpth}}/bin'
                      state: directory
              
                  - name: Transfer
                    copy: src={{ item.src }} dest={{ item.dest }} mode=0775
                    with_items:
                    - { src: '../utils/cpldupd', dest: '{{rpth}}/cpldupd' }
                    - { src: '../utils/bin/cpldupd', dest: '{{rpth}}/bin/cpldupd' }
              

              【讨论】:

              • 如果您有新问题,请点击 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。 - From Review
              • 这不是一个问题,而是另一个使用 Ansible 将文件从多个目录复制到多个目录的更完整示例。它添加了远程文件模式。将其添加为评论可能更合适,但我还没有足够的声誉。我看到你过去也使用过这种技术stackoverflow.com/questions/28347717/…
              • 我有点苛刻,抱歉:当我审查这个问题时,感觉你想强调如何处理文件权限,但这不在原来的问题中(因此是一个新的问题)问题可能是突出这一点的好选择);你说得对,评论感觉更适合反对你提到的答案;我还看到使用mode 已经出现在其他几个答案中,所以不需要再说一遍。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2017-07-05
              • 1970-01-01
              • 2022-12-06
              • 2016-08-12
              • 1970-01-01
              • 2014-10-19
              • 1970-01-01
              相关资源
              最近更新 更多