首页/系统与基础设施/自动化运维速查/命令模块与幂等模块的选择依据
Ansible 核心70 条

命令模块与幂等模块的选择依据

命令模块直接执行程序,不经过 shell,因此不支持管道、重定向与变量展开;shell 模块通过 shell 执行,能力更强但副作用与风险也更大;两者默认都把执行视为变更且不具备幂等判断。专用状态型模块自带幂等与差异报告,是首选;确需执行命令时,用存在性判断、变更条件或状态比较把它包装成可重复执行的任务。

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌​​​​‌​‌‌‌​‌​‌​‌‌‌​‌​​​‌‌​‌‌‌‌​‌‌​‌‌​‌​‌‌​​​​‌​‌‌‌​‌​​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌​‌‌‌​​​‌​‌‌‌‌​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​‌‌​‌‌​‌​‌‌​​​​‌​‌‌​‌‌‌​​‌‌​​‌​​​​‌​‌‌​‌​‌‌‌​‌‌​​‌‌‌​​‌‌​​‌​‌‌​‌​‌‌​‌​​‌​‌‌​​‌​​​‌‌​​‌​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌‌‌​‌‌‌​‌​​​‌‌​​‌​‌​‌‌​‌‌‌​​‌‌‌​‌​​​​‌​‌‌​‌​‌‌​‌‌​‌​‌‌​‌‌‌‌​‌‌​​‌​​​‌‌‌​‌​‌​‌‌​‌‌​​​‌‌​​‌​‌​​‌​‌‌​‌​‌‌​​​‌‌​‌‌​‌​​​​‌‌​‌‌‌‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌​​‌​‌​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​

两类模块的差别

命令模块执行一个可执行程序,参数以列表形式传入,不经过 shell,因此管道、通配符展开、重定向与环境变量赋值都不生效,适合参数固定、无需 shell 特性的场景。shell 模块通过系统的 shell 执行整段字符串,支持管道与重定向,但也因此更容易写出不可重复、易受注入影响的内容。两者在执行报告里默认都被视为「已变更」,不会判断目标是否已经是期望状态,这是与状态型模块最重要的差别。

基本信息

命令模块直接执行程序,不经过 shell
shell 模块通过 shell 执行,支持管道与重定向
共同限制默认不具备幂等判断,总是报告已变更
优先选择装包、写文件、管服务等用状态型模块

包装成幂等的办法

  • 存在性判断:目标任务已完成时直接跳过,避免重复执行。
  • 标注变更条件:命令本身不具备变更语义时,用条件表达式描述真实变更。
  • 标注失败条件:有些命令用非零返回码表达「无变化」,需要显式改判。
  • 校验结果:执行后检查实际状态,而不是只看返回码。
  • 限制重试:无幂等保证的命令不要开启自动重试。
  • 说明原因:在任务注释里写清为什么不用专用模块,便于评审。

同一件事的两种写法

同一件事的两种写法
# 命令模块 + 存在性判断:可重复执行
- name: 初始化数据目录(仅当未初始化时)
  ansible.builtin.command:
    cmd: /opt/app/bin/init-db --path /var/lib/app
    creates: /var/lib/app/initialized.flag   # 已存在则跳过,保证幂等

# shell 模块:需要管道时必须显式声明,并补齐判断
- name: 统计并写入上报文件
  ansible.builtin.shell:
    cmd: |
      journalctl -u app --since '1 hour ago' | grep -c ERROR > /var/tmp/app_err.cnt
  args:
    executable: /bin/bash            # 明确使用哪个 shell
  changed_when: false                # 仅采集,不算变更

选择判读

需求建议模块原因
安装软件包包管理模块自带幂等与版本判断
下发配置模板或复制模块有差异比对与备份
启停服务服务模块状态型语义
执行不支持的工具命令命令模块加判断无专用模块时的兜底
需要管道与重定向shell 模块加判断命令模块不支持 shell 特性
仅采集信息命令模块并标注不算变更避免误报变更
把命令模块的变更语义标对很重要:仅做查询的任务若报告已变更,会让执行报告的变更数量失去参考价值,掩盖真正的变更。
shell 模块会把整段字符串交给 shell 解释,变量来自外部输入时存在注入风险;能用命令模块表达时不要使用 shell。

易错点

  • 用命令模块执行需要管道的命令:因不经过 shell 而失败,报错信息容易被误读为命令不存在
  • 命令模块不写存在性判断:重复执行产生重复结果,重试时影响被放大
  • 把查询任务标成变更:执行报告的变更数量被虚高,真正的变更被淹没
  • 未限制外部输入:shell 模块中拼接外部变量,存在命令注入风险

数据来源与参考

  • Ansible 官方文档:command 与 shell 模块说明
  • Ansible 官方文档:changed_when 与 failed_when 条件
  • Ansible 官方文档:模块幂等性说明

整理校对:其其网ICT文档中心 · 本页地址:docs.qiqicto.com/automation/command-vs-idempotent-module-choice.html

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌​​​​‌​‌‌‌​‌​‌​‌‌‌​‌​​​‌‌​‌‌‌‌​‌‌​‌‌​‌​‌‌​​​​‌​‌‌‌​‌​​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌​‌‌‌​​​‌​‌‌‌‌​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​‌‌​‌‌​‌​‌‌​​​​‌​‌‌​‌‌‌​​‌‌​​‌​​​​‌​‌‌​‌​‌‌‌​‌‌​​‌‌‌​​‌‌​​‌​‌‌​‌​‌‌​‌​​‌​‌‌​​‌​​​‌‌​​‌​‌​‌‌​‌‌​‌​‌‌‌​​​​​‌‌​‌‌‌‌​‌‌‌​‌​​​‌‌​​‌​‌​‌‌​‌‌‌​​‌‌‌​‌​​​​‌​‌‌​‌​‌‌​‌‌​‌​‌‌​‌‌‌‌​‌‌​​‌​​​‌‌‌​‌​‌​‌‌​‌‌​​​‌‌​​‌​‌​​‌​‌‌​‌​‌‌​​​‌‌​‌‌​‌​​​​‌‌​‌‌‌‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌​​‌​‌​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​