如何在Ansible中正确使用变量存储的shell输出执行后续任务
Ansible提取包列表并安装失败问题
需求
- 将代码仓库克隆到远程节点
- 使用
grep从git仓库内的文本文件中提取包列表 - 将包列表加载到Ansible变量并通过
apt/package模块安装
现有Playbook
--- - hosts: all become: true vars: username: foobar tasks: - name: Install git package package: name: git state: present - name: Clone GIT Repo git: repo: https://github.com/somerepo/.dotfiles.git dest: /home/{{ username }}/.dotfiles clone: yes version: master update: yes force: yes - name: Set permission on folder ~/.dotfiles file: dest: /home/{{ username }}/.dotfiles recurse: yes owner: "{{ username }}" group: "{{ username }}" mode: "0775" - name: Extract list of needed tools from install.sh shell: cmd: grep "^tools=" /home/{{ username }}/.dotfiles/install.sh | tr '"' " " | cut -c7- register: grep_output - name: Install following packages "{{ grep_output }}" apt: name: "{{ grep_output }}" state: present update_cache: yes
提取包的Shell命令及输出
用于提取包列表的命令:
grep "^tools=" install.sh |tr '"' " " | cut -c7-
命令标准输出:
zsh neovim vim tmux ranger stow wget curl git fzf
错误信息
执行Playbook时触发如下错误:
PLAY [all] ******************************************************************************************************************* TASK [Gathering Facts] ******************************************************************************************************* [WARNING]: Platform linux on host vm-mint21 is using the discovered Python interpreter at /usr/bin/python3.10, but future installation of another Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible-core/2.12/reference_appendices/interpreter_discovery.html for more information. ok: [vm-mint21] TASK [Install git package] *************************************************************************************************** ok: [vm-mint21] TASK [Clone GIT Repo] ******************************************************************************************************** changed: [vm-mint21] TASK [Set permission on folder ~/.dotfiles] ********************************************************************************** changed: [vm-mint21] TASK [Extract list of needed tools from install.sh] ************************************************************************** changed: [vm-mint21] TASK [Install following packages "{'changed': True, 'stdout': ' zsh neovim vim tmux ranger stow wget curl git fzf ', 'stderr': '', 'rc': 0, 'cmd': 'grep "^tools=" /home/soeren/.dotfiles/install.sh | tr \'"\' " " | cut -c7-', 'start': '2022-09-12 22:33:37.056914', 'end': '2022-09-12 22:33:37.061264', 'delta': '0:00:00.004350', 'msg': '', 'stdout_lines': [' zsh neovim vim tmux ranger stow wget curl git fzf '], 'stderr_lines': [], 'failed': False}"] *** fatal: [vm-mint21]: FAILED! => {"changed": false, "msg": "argument 'package' is of type <class 'dict'> and we were unable to convert to list: <class 'dict'> cannot be converted to a list"} PLAY RECAP ******************************************************************************************************************* vm-mint21 : ok=5 changed=3 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
核心错误提示(已翻译):
参数'package'是字典类型,无法转换为列表:字典不能转为列表
问题原因
register: grep_output会将整个shell任务的返回结果(包含stdout、stderr、rc等字段的字典)存入变量,而你直接将这个字典传给了apt模块的name参数——该参数需要的是包名列表,而非字典,因此触发类型转换错误。
解决方案
方案1:直接使用stdout并转换为列表
修改安装任务,通过grep_output.stdout获取命令的标准输出,再用split()将空格分隔的字符串转为列表:
- name: Install required packages apt: name: "{{ grep_output.stdout.split() }}" state: present update_cache: yes
方案2:用Ansible原生模块替代Shell(推荐)
避免依赖shell命令,改用slurp读取文件内容,结合正则表达式提取包列表,更符合Ansible最佳实践:
# 替换原有的shell提取任务 - name: Read install.sh content slurp: path: /home/{{ username }}/.dotfiles/install.sh register: install_sh_content - name: Extract tools list into variable set_fact: tools_list: "{{ (install_sh_content.content | b64decode) | regex_search('^tools=\"(.*)\"', '\\1') | first | split() }}" - name: Install required packages apt: name: "{{ tools_list }}" state: present update_cache: yes
内容的提问来源于stack exchange,提问作者edinazzu
相关产品推荐
相关产品推荐

