优先用 ansible_facts['os_family'] 判断系统大类,因其稳定;需区分同源不同名发行版时才用 ansible_distribution。when 中变量不加 {{ }},因解析的是 python 表达式而非 jinja2 模板。

直接结论:用 when + ansible_distribution 或 ansible_facts['os_family'] 判断发行版,但变量不加 {{ }},且注意大小写和空格。
ansible_distribution 和 os_family 该怎么选?
两者都能判断系统类型,但语义和稳定性不同:
-
ansible_distribution是字符串,比如"CentOS"、"Ubuntu"、"Kylin Linux Advanced Server"—— 精确但易受命名变化影响(比如 CentOS Stream 8 和 9 的值就不同) -
ansible_facts['os_family']是归类后的抽象值,比如"RedHat"、"Debian"、"SUSE"—— 更稳定,适合跨大类兼容(如所有 RHEL 系家族统一处理) - 如果目标是区分
CentOS和Rocky这类同源但名不同的系统,必须用ansible_distribution;如果只是“RPM 系统装 yum 包,DEB 系统装 apt 包”,优先用os_family
when 中变量为什么不能写 {{ ansible_distribution }}?
因为 when 解析的是 Python 表达式上下文,不是 Jinja2 模板上下文。Ansible 会自动把 facts 和变量注入到这个表达式环境里,所以直接写 ansible_distribution == "Ubuntu" 就行。
写成 {{ ansible_distribution == "Ubuntu" }} 或 {{ ansible_distribution }} == "Ubuntu" 都会报错:invalid when statement 或解析为字符串字面量。
常见错误现象:
- 任务始终跳过,但
ansible all -m setup -a 'filter=ansible_distribution'明明显示值是对的 → 很可能多写了{{ }} - 报错
error while evaluating conditional: 'str' object has no attribute 'split'→ 把一个字符串当成了对象调用方法,也是因误用了模板语法
多个发行版或复杂逻辑怎么写才安全?
避免一行写太长的 or / and,推荐用 YAML list 形式,语义清晰且不易漏括号:
- name: Install nginx repo on RHEL-like
yum_repository:
name: nginx
baseurl: https://nginx.org/packages/centos/$releasever/$basearch/
when:
- ansible_facts['os_family'] == "RedHat"
- ansible_facts['distribution_major_version'] | int >= 7
- name: Install nginx repo on Debian-like
apt_repository:
repo: "deb https://www.php.cn/link/6b603231dea237cc9b6c447d988cd6f2 {{ ansible_facts['distribution']|lower }} nginx"
when:
- ansible_facts['os_family'] == "Debian"
- ansible_facts['distribution'] not in ["Kali", "Parrot"]
注意点:
-
ansible_facts['distribution_major_version'] | int必须显式转整型,否则字符串"8"和数字8比较会恒为 False - 用
not in排除小众变种比堆and distribution != "Kali" and distribution != "Parrot"更可读 - 如果依赖
ansible_distribution,建议先用debug: var=ansible_distribution确认实际值——麒麟、UOS、OpenEuler 的返回值常带空格或版本后缀,直接硬匹配容易失败
-
when 跳过任务但没提示,怎么确认它到底有没有生效?
默认输出里 skipping: 行很容易被刷屏淹没。调试时加两个东西:
- 执行时加
-v(至少一次),能看到完整条件表达式求值过程,例如:skipping: [host] => {"reason": "Conditional result was False"} - 在关键任务前加一个
debug: msg="I'm on {{ ansible_distribution }}"并同样配when,快速验证变量值和条件逻辑是否一致 - 别依赖
gather_facts: no下的when—— 所有ansible_*变量都来自 facts,关了就全不可用,此时条件永远不成立
最常被忽略的一点:条件里引用的变量如果本身未定义(比如自定义变量拼错名),when 默认当作 False 处理且不报错,任务静默跳过。务必先用 debug 确认变量存在。











