介绍
在远程主机通过 shell(默认 /bin/sh) 执行命令,支持管道 |、重定向 > >>、&、shell变量、通配符
模块全名:ansible.builtin.shell(2.10+集合命名,旧版直接写 shell)
参数
| 参数 | 说明 |
|---|---|
| cmd | 要执行的shell命令;playbook中也可以直接写命令(free_form写法,没有free_form这个真实参数) |
| chdir | 执行命令前,先切换到该目录 |
| creates | 文件路径:如果文件已存在,则跳过本次任务(做幂等) |
| removes | 文件路径:如果文件不存在,则跳过本次任务 |
| executable | 指定shell解释器绝对路径,例 /bin/bash;默认 /bin/sh |
| stdin | 设置命令标准输入 |
| stdin_add_newline | bool,默认yes;是否给stdin末尾追加换行符 |
| warn | bool,默认yes;是否开启ansible对shell模块的警告(长命令建议关闭) |
返回结果字段:
rc返回码、stdout标准输出、stderr错误输出、stdout_lines输出按行列表。
Ad-hoc 命令用法
基础:查看主机名
单引号,变量在远程解析
ansible web -m shell -a 'echo $HOSTNAME'
管道过滤进程
ansible web -m shell -a 'ps aux | grep nginx | grep -v grep'
chdir:先cd到/var/log,执行ls
ansible web -m shell -a 'ls' -a chdir=/var/log
creates:/tmp/ok.txt存在,就不执行
ansible web -m shell -a 'touch /tmp/ok.txt' -a creates=/tmp/ok.txt
指定bash执行
ansible web -m shell -a 'echo $BASH_VERSION' executable=/bin/bash
shell vs command 比较
| 模块 | 执行方式 | 支持管道/重定向 | 幂等性 | 推荐 |
|---|---|---|---|---|
| shell | 拉起shell进程执行 | ✅ 支持 | ❌ 命令本身不幂等 | 复杂命令、管道、脚本 |
| command | exec直接执行程序,不经过shell | ❌ 不支持 > 等管道 |
❌ | 简单命令,优先使用,更安全 |
原则:能使用command就不用shell,shell有shell注入风险。
注意事项
1. 幂等性问题
shell模块本身不具备幂等。多次执行可能重复操作。
用 creates/removes + changed_when 来模拟幂等:
shell: touch /tmp/xxx
args:
creates: /tmp/xxx
2. 引号坑(Ad-hoc)
- 单引号
'echo $var':变量在远程主机解析 ✅ - 双引号
"echo $var":变量在本地ansible主机解析 ❌
3. 多行shell脚本:| yaml多行字符串
- name: 多行脚本
shell: |
set -e
echo "start"
ls /tmp
echo "done"
args:
executable: /bin/bash
4. 安全风险
shell会做命令替换,不要直接传入不可信外部变量,防止shell注入。
5. 换行、特殊字符
复杂命令建议用 args 拆分,或者放到脚本文件用 script 模块。
常见返回值判断
- name: run cmd
shell: cat /etc/hosts
register: out
failed_when: out.rc !=0
# out.stdout 字符串
# out.stdout_lines 数组
# out.stderr 错误信息
# out.rc 返回码,0成功
shell / script / raw 简要区分
shell:远程主机调用shell执行一段命令;支持become、环境变量script:把本地控制节点脚本上传到远程执行,不需要shell语法raw:底层ssh直接执行,不支持become、async、环境变量;无python环境时用
最佳实践
- 简单命令优先
command;必须管道/重定向才选shell - shell任务尽量加
changed_when: false(查询类)或creates(修改类)减少误报changed - 长脚本,优先把脚本文件分发后用
script,不要写超大多行shell - 指定bash时使用
executable: /bin/bash,因为/bin/sh不支持bash特有语法