You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写Ansible Copy任务实现多文件批量复制到多JVM目录?

问题背景

每台RHEL服务器的/etc/rc.d/init.d/目录下,有一个名为JVMNAMES的文件,文件内每行记录一个JVM名称,内容示例如下:

abc-def01
bcd-efg02
cde-fgh01

需求是循环将四个.sh文件复制到每个JVM的bin目录中。此前通过Shell脚本实现该需求,脚本内容如下:

LIST=/etc/rc.d/init.d/JVMNAMES

for i in `cat $LIST`
do      
  echo "Updating the needed .sh files for JVM: '$i'..."
  cp /usr/apache/tomcat/tomcat-current/bin/catalina.sh /usr/apache/tomcat/$i/bin/
  cp /usr/apache/tomcat/tomcat-current/bin/version.sh /usr/apache/tomcat/$i/bin/
  cp /usr/apache/tomcat/tomcat-current/bin/startup.sh /usr/apache/tomcat/$i/bin/
  cp /usr/apache/tomcat/tomcat-current/bin/shutdown.sh /usr/apache/tomcat/$i/bin/
done

目前编写了如下Ansible Playbook,但尚未运行,希望得到优化建议:

- name: Copy the needed .sh files to the bin directory of each JVM
  ansible.builtin.copy:
    src: "/usr/apache/tomcat/tomcat-current/bin/{{ item }}"
    dest: "/usr/apache/tomcat/{{ jvm_idx }}/bin/"
    owner: mwuser
    group: mwadmin
    mode: "u+rwx,g+rx,o=rx"
  with-items:
  - catalina.sh
  - version.sh
  - startup.sh
  - shutdown.sh
  loop: "{{ lookup('file', '/etc/rc.d/init.d/JVMNAMES') }}"
  loop_control:
    index_var: jvm_idx
优化建议

你的Playbook存在语法冲突和逻辑问题,以下是更合理的实现方案:

核心问题修正

原Playbook同时混用了旧语法with-items和新语法loop,这会导致循环逻辑混乱;且直接读取文件内容未处理换行符,可能出现无效的JVM名称。

优化后Playbook

- name: 定义JVM列表和目标文件列表
  set_fact:
    jvm_list: "{{ lookup('file', '/etc/rc.d/init.d/JVMNAMES').splitlines() }}"
    target_sh_files:
      - catalina.sh
      - version.sh
      - startup.sh
      - shutdown.sh

- name: 复制sh文件到每个JVM的bin目录
  ansible.builtin.copy:
    src: "/usr/apache/tomcat/tomcat-current/bin/{{ sh_file }}"
    dest: "/usr/apache/tomcat/{{ jvm_name }}/bin/"
    owner: mwuser
    group: mwadmin
    mode: "u+rwx,g+rx,o=rx"
  loop: "{{ jvm_list | product(target_sh_files) | list }}"
  loop_control:
    loop_var: jvm_sh_pair
    label: "Copying {{ jvm_sh_pair.1 }} to JVM {{ jvm_sh_pair.0 }}"
  vars:
    jvm_name: "{{ jvm_sh_pair.0 }}"
    sh_file: "{{ jvm_sh_pair.1 }}"

优化点说明

  • 使用product过滤器实现两个列表的笛卡尔积,完美对应“每个JVM复制所有sh文件”的嵌套循环逻辑
  • splitlines()将读取的文件内容拆分为每行一个元素的列表,避免换行符干扰
  • loop_control的label参数让执行日志更简洁,只显示关键操作信息
  • 将列表定义为变量,后续修改JVM或文件列表时无需改动核心任务代码
  • 统一使用Ansible推荐的loop语法,弃用已过时的with-items

可选增强优化

  • 添加JVM目录存在性校验,防止复制到不存在的路径报错:
    pre_tasks:
      - name: 检查JVM的bin目录是否存在
        ansible.builtin.stat:
          path: "/usr/apache/tomcat/{{ item }}/bin"
        register: jvm_bin_check
        loop: "{{ jvm_list }}"
    
    - name: 复制sh文件到每个JVM的bin目录
      ansible.builtin.copy:
        ...
      when: (jvm_bin_check.results | selectattr('item', 'equalto', jvm_name) | first).stat.exists
    

内容的提问来源于stack exchange,提问作者Jason Skeel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 05:17:28