Ansible ad-hoc的command和shell模块的区别

本文解析了Ansible中ad-hoc命令的功能及其应用场景,对比了command与shell模块的区别,并通过实例说明了如何正确使用这两种模块来执行远程命令。

背景

Ansible中有一个很重要的功能就是可以执行ad-hoc命令,可能有些人不懂ad-hoc这个词的意思,它表示即时的意思,或者说随意的意思。

与之相对的是ansible playbook功能,playbook适用于批量部署环境,一般不用经常改动。而ad-hoc命令适用于业务变更等操作场景,比如批量部署一个配置文件,重启某个服务,安装一些包等。

ad-hoc命令中有两个模块:command, shell。很多人不知道他们的区别是什么,其实很简单。

原理解析

你在终端输入一条ad-hoc命令后,ansible会生成一个可执行python脚本文件,然后把它拷贝到远程机器上执行,这个脚本中包含了命令行的所有信息。

如果你用的是command或shell模块,那么脚本中调用的是subprocess.Popen(args,*kwargs)函数,command和shell的区别就在于command模块使用shell=True,而shell模块使用shell=False,就是一个调用了shell,一个没有。

官方文档中是不建议使用shell=True的,因为这可能导致shell injection安全问题,但是有些情况下用shell模块就很方便,比如我要批量删除一些文件, 

ansible -i inventory all -m command -a "rm -f /etc/yum.repos.d/CentOS*.repo" -U root -s -f 50 -kK

你如果执行以上命令的话,是不会删除掉那些文件的,为什么?

因为你的命令行中包含了通配符*号,通配符必须要有在shell环境中才能被识别出,不然,它只能删除CentOS*.repo这一个文件。

所以你需要执行以下命令才能成功

ansible -i inventory all -m shell -a "rm -f /etc/yum.repos.d/CentOS*.repo" -U root -s -f 50 -kK

而这两个命令所生成的可执行脚本的区别就一行

< MODULE_ARGS = 'rm -f /etc/yum.repos.d/CentOS*.repo'

---

> MODULE_ARGS = 'rm -f /etc/yum.repos.d/CentOS* #USE_SHELL'

 

看到这里,想必已经让你清晰很多了吧!

有问题可以发表评论!

 

推荐一个非常好的关于容器技术的公众号,有兴趣的可以关注!

å¨è¿éæå¥å¾çæè¿°

<think>好的,用户现在想要使用Ansiblead-hoc模式file模块来删除/tmp目录下的所有文件,而且不能用commandshell模块。首先,我需要回顾一下之前给出的Playbook方案,那里用了find模块来列出所有文件,然后循环删除。但ad-hoc命令是单行的,不能直接写循环,所以得想办法简化步骤。 用户可能是在寻找一种快速的方法,不需要写完整的Playbook,直接用一行命令解决问题。但Ansiblead-hoc模式在处理复杂任务时有局限性,特别是需要多个步骤的任务,比如先查找再删除。所以得考虑如何结合模块的功能。 首先,ad-hoc命令通常结构是ansible 主机 -m 模块 -a "参数"。但这里需要两个步骤:查找文件删除文件。由于不能使用commandshell模块,只能用Ansible模块本身的功能。想到可以用find模块来获取文件列表,然后传递给file模块删除,但如何在ad-hoc中实现循环呢? 不过,Ansiblead-hoc模式不支持像Playbook那样的循环结构,比如loop。可能需要利用模块的参数或者Ansible的特性来实现。例如,find模块可以返回结果,然后通过变量传递给后续命令,但ad-hoc模式下无法直接串联两个任务。 有没有其他方法?比如使用通配符路径,但file模块的path参数是否支持通配符呢?根据Ansible的文档,file模块的path参数不支持通配符,直接指定/tmp/*可能无法生效,因为模块会认为这是一个不存在的路径,导致操作失败。 那有没有其他模块可以做到这一点?比如使用synchronize模块或者其他模块,但用户明确要求使用file模块,所以必须用file模块结合其他方法。 或者,是否可以利用Ansible的with_fileglob循环?不过with_fileglob是在Playbook中使用的,无法在ad-hoc命令中使用。这时候可能需要变通,比如使用shell模块,但用户明确禁止使用commandshell模块,所以这条路行不通。 这时候可能需要回到之前的思路,即使用find模块file模块结合,但在ad-hoc模式下如何执行两次任务呢?可能需要分两次运行ad-hoc命令,第一次用find模块获取文件列表,保存到变量,第二次用file模块删除这些文件。不过ad-hoc模式如何保存变量并传递给后续命令呢? 实际上,这在ad-hoc模式下是不可能的,因为每次ad-hoc命令都是独立的,无法共享变量。所以用户可能需要接受ad-hoc模式的限制,或者改用Playbook。但用户坚持要使用ad-hoc模式,所以必须找到另一种方法。 有没有可能通过一个复杂的ad-hoc命令实现?比如使用Ansible的registerset_fact模块,但同样,这在单行命令中难以实现。或者,是否可以在一个命令中调用多个模块?比如通过管道符或者其他方式,但Ansiblead-hoc模式不支持这种操作。 这时候可能需要重新考虑用户的需求。用户可能希望快速清理/tmp目录,而使用Playbook虽然更合适,但用户可能因为临时需求而想要用ad-hoc命令。如果必须使用ad-hocfile模块,可能需要接受无法完全删除所有文件的可能,或者需要多次运行命令。 或者,是否可以结合使用find模块的输出xargs之类的工具,但同样,这需要调用shell命令,而用户不允许使用commandshell模块。因此,这可能不可行。 综上所述,或许只能通过多次运行ad-hoc命令,首先找到所有文件,然后逐一删除。但如何将find的结果传递给file模块呢?可能需要在每次执行时手动处理输出结果,但这显然不实际。 或者,是否可以使用Ansible的变量查询功能?比如,在ad-hoc命令中调用find模块,然后将结果通过变量传递给另一个ad-hoc命令。例如: ansible all -m find -a "paths=/tmp recurse=no" --vars "tmp_files={{ ansible_find.files }}" 然后再次调用file模块ansible all -m file -a "path={{ item.path }} state=absent" --extra-vars "tmp_files=..." 但这在ad-hoc模式下不可行,因为变量无法在两次命令之间传递。因此,这种方法行不通。 这时候可能需要告诉用户,在ad-hoc模式下无法直接使用file模块删除/tmp下的所有文件,而不借助shellcommand模块。或者,是否存在其他变通方法? 突然想到,可以使用Ansible的循环功能在ad-hoc命令中,但需要特定的语法。例如,使用ansible-m参数指定模块,然后通过-a传递参数,结合with_items。不过,Ansiblead-hoc模式是否支持这种结构? 例如: ansible all -m file -a "path={{ item }} state=absent" --args='with_items: "{{ lookup('fileglob', '/tmp/*', wantlist=True) }}"' 但这样的语法在ad-hoc模式下可能无法正确解析,因为--args参数不支持这种结构。而且,lookup插件在ad-hoc中的使用可能受限。 这时候可能需要承认,使用纯ad-hoc命令file模块无法完成这个任务,必须结合find模块循环,而ad-hoc模式不支持这样的复杂操作。因此,可能需要建议用户使用shell模块,但用户明确禁止了这一点,所以陷入困境。 或者,是否可以使用Ansible的script模块,但同样属于命令执行类模块,可能被用户禁止。 这时候可能需要给出一个折中的方案,即在ad-hoc模式下分两步执行:首先使用find模块列出所有文件,然后手动构造一个包含这些文件路径的列表,再传递给file模块。但这需要手动处理输出,对于自动化来说不实际。 或者,是否可以使用Ansible的register功能,将find的结果保存到变量,然后在后续命令中使用该变量?例如: ansible all -m find -a "paths=/tmp" --register tmp_files 然后: ansible all -m file -a "path={{ item.path }} state=absent" --extra-vars "{{ tmp_files }}" 但ad-hoc模式不支持这种变量传递,因此不可行。 这时候可能需要面对现实,告诉用户这在ad-hoc模式下无法实现,或者需要使用Playbook。但用户可能希望无论如何都要用ad-hoc,所以需要寻找可能的解决方案。 另一个思路是,是否可以利用Ansible的raw模块,但同样属于命令执行,被用户禁止。 或者,是否可以使用Ansible模块参数中的通配符,比如path: /tmp/*,但根据Ansible的file模块文档,path参数必须是一个确切存在的路径,不支持通配符,因此删除/tmp/*这样的路径会失败,因为/tmp/*本身不存在,file模块会报错。 因此,可能需要告诉用户,无法在ad-hoc模式下仅使用file模块完成任务,必须结合其他模块或方法,或者改用Playbook。 不过,用户可能坚持要找到一种方法,所以可能需要再次仔细检查Ansible的file模块是否有其他参数可用。例如,是否可以使用state: absent结合递归参数?但file模块的递归删除是当path是一个目录时,设置state: absent会删除整个目录及其内容。但用户需要保留/tmp目录本身,只删除其内容。因此,这种方法不可行,因为删除/tmp目录后需要重新创建,但可能在多任务中处理。 不过,用户的需求是删除/tmp下的所有文件,同时保留/tmp目录本身。如果使用file模块删除/tmp,然后重新创建它,可能会导致权限问题,或者中间有进程依赖/tmp目录而出现问题。 因此,这种方法不可取。 总结,可能在ad-hoc模式下,无法仅使用file模块完成这个任务,而必须结合find模块循环,这在ad-hoc中难以实现,因此需要建议用户使用Playbook,或者接受使用shell模块的风险。 不过,用户明确要求不许用commandshell模块,所以必须找到其他方法。 这时候可能需要使用一个复杂的ad-hoc命令,通过find模块xargs类似的方法,但如何实现? 例如,可以将find模块的结果传递给file模块,但需要将多个路径作为参数传递给file模块。在Ansible中,可以使用json_query来提取路径列表,然后在另一个ad-hoc命令中使用。例如: ansible all -m find -a "paths=/tmp file_type=any" | jq -r '.files[].path' | xargs -I {} ansible all -m file -a "path={} state=absent" 但这里使用了shell管道xargs,属于调用shell命令,违反了用户的要求,所以不可行。 因此,最终可能的结论是:在ad-hoc模式下,仅使用file模块无法完成这个任务,必须结合其他模块或使用Playbook。 但用户可能不接受这个答案,所以需要再仔细思考是否有其他可能性。 突然想到,Ansible的file模块有一个参数可以删除目录的内容,但保留目录本身吗?比如类似于rmdir的内容,但查阅文档后发现,file模块的state: absent在应用于目录时,会递归删除整个目录,包括其内容,但不会保留目录本身。因此,无法直接使用file模块删除目录内容而保留目录。 那有没有其他模块可用?比如community.general.cleanup模块,但用户要求使用file模块,所以这可能不符合要求。 综上所述,可能必须告诉用户,在ad-hoc模式下无法仅使用file模块完成任务,必须使用Playbook或接受使用其他模块。但用户的问题明确要求使用ad-hocfile模块,所以可能需要提供一个变通方案,即使不够完美。 可能的解决方案是分两步: 1. 使用find模块ad-hoc命令获取所有文件路径。 2. 手动将路径列表传递给file模块ad-hoc命令。 但步骤2需要手动处理,无法自动化,因此不实际。 或者,是否存在Ansible模块可以读取变量文件并循环处理?例如,使用include_varsfile模块,但这同样需要Playbook。 因此,最终的结论是,无法在ad-hoc模式下仅使用file模块实现删除/tmp目录下的所有文件,而必须使用Playbook结合findfile模块,或者使用shell模块。但用户不允许使用shell,所以只能建议使用Playbook。 不过,用户可能仍然希望得到一个ad-hoc的解决方案,因此可能需要寻找一种变通方式,例如使用多个ad-hoc命令,尽管不够优雅,但可能勉强可行。 例如,可以运行: ansible all -m find -a "paths=/tmp recurse=no file_type=any" --register tmp_files 然后解析该命令的输出,提取文件路径,再构造另一个ad-hoc命令。但这种方法需要手动处理输出,不适合自动化。 或者,是否可以使用Ansible的debug模块将变量输出为JSON,然后用jq处理?但同样需要shell命令,违反用户要求。 因此,可能必须承认在ad-hoc模式下无法实现,而用户需要改用Playbook。这可能就是正确的答案,尽管不是用户希望听到的,但技术上确实如此。 所以,在回答时,应该说明在ad-hoc模式下无法直接实现,必须使用Playbook,或者接受使用shell模块。但用户明确要求不使用shell,所以正确的答案是指导用户使用Playbook,或者解释其限制。</think>### **通过 Ansible Ad-Hoc 模式清空 `/tmp` 目录的步骤(仅用 `file` 模块)** --- #### **核心难点** - **Ad-Hoc 模式的限制**: 无法直接实现多步骤逻辑(如先查找文件再循环删除)。 - **`file` 模块的限制**: 不支持通配符(如 `/tmp/*`),直接操作会报错。 - **唯一可行方法**: 使用 `find` 模块获取文件列表,再通过动态生成的路径传递给 `file` 模块--- ### **操作步骤** #### **1. 分步执行 Ad-Hoc 命令** ```bash # 第一步:查找 /tmp 目录下的所有直接子项(文件、目录、符号链接等) ansible all -m ansible.builtin.find -a "paths=/tmp recurse=no file_type=any" --become # 第二步:手动提取路径并构造删除命令 # 假设上一步输出的 JSON 结果中文件路径为 /tmp/file1、/tmp/dir1 等 # 手动将这些路径拼接到以下命令中: ansible all -m ansible.builtin.file -a "path=/tmp/file1 state=absent" --become ansible all -m ansible.builtin.file -a "path=/tmp/dir1 state=absent" --become ``` --- ### **为何无法完全自动化?** | **问题** | **解释** | |------------------------|--------------------------------------------------------------------------| | **Ad-Hoc 无循环支持** | 无法直接在单条命令中遍历 `find` 模块的结果。 | | **路径需手动提取** | `find` 模块的输出需人工解析,无法自动传递到 `file` 模块。 | | **缺乏幂等性控制** | 手动操作可能导致重复执行或遗漏。 | --- ### **推荐替代方案** #### **使用 Playbook(自动化推荐)** ```yaml - name: Clean /tmp with file module hosts: all become: yes tasks: - name: Find items in /tmp ansible.builtin.find: paths: /tmp recurse: no file_type: any register: tmp_items - name: Delete all found items ansible.builtin.file: path: "{{ item.path }}" state: absent loop: "{{ tmp_items.files }}" ``` --- ### **关键注意事项** 1. **权限问题** - 必须使用 `--become` 提权(因 `/tmp` 可能包含其他用户的文件)。 2. **安全风险** - 直接删除 `/tmp` 下的文件可能导致正在运行的进程异常(如临时文件被占用)。 3. **操作建议** - **测试环境验证**: 先在非生产环境测试命令逻辑。 - **避免递归删除**: 确保 `recurse=no` 仅操作 `/tmp` 的直接子项。 --- ### **总结** | **方法** | **适用场景** | **缺点** | |------------------|---------------------------------|---------------------------------------| | **Ad-Hoc + 手动** | 临时清理少量已知路径 | 效率低、易出错 | | **Playbook** | 自动化、批量操作 | 需预先编写 YAML 文件 | **结论**: 若必须使用 Ad-Hoc 模式,需手动解析路径并多次执行删除命令;**强烈推荐改用 Playbook 实现自动化**。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值