如何在Ansible Playbook中运行含引号、括号与重定向的命令
在Ansible Playbook中正确执行修改composer.json的bash命令
我有一条可正常执行的bash命令,用于给composer.json添加PSR-4自动加载规则:
cat <<< $(jq --indent 4 '.autoload."psr-4" += { "Modules": "Modules/" }' me/composer.json) > me/composer.json
但将其放入Ansible Playbook中执行时出现多种错误,以下是尝试过程及解决方案:
尝试1:使用shell模块
Playbook代码
--- - name: modules autoload shell: | cat <<< $(jq --indent 4 '.autoload."psr-4" += { "Modules": "Modules/" }' me/composer.json) > me/composer.json
报错信息
fatal: [127.0.0.1]: FAILED! => {"changed": true, "cmd": "cat <<< $(jq --indent 4 '.autoload.\"psr-4\" += { \"Modules\\\": \"Modules/\" }' me/composer.json) > me/composer.json", "delta": "0:00:00.001537", "end": "2023-03-13 01:06:28.268890", "msg": "non-zero return code", "rc": 2, "start": "2023-03-13 01:06:28.267353", "stderr": "/bin/sh: 1: Syntax error: redirection unexpected", "stderr_lines": ["/bin/sh: 1: Syntax error: redirection unexpected"], "stdout": "", "stdout_lines": []}
错误原因
Ansible的shell模块默认使用/bin/sh执行命令,而<<<(here-string)是bash专属特性,并非所有sh兼容shell都支持,因此触发语法错误。
尝试2:使用command模块
Playbook代码
--- - name: modules autoload command: | cat <<< $(jq --indent 4 '.autoload."psr-4" += { "Modules": "Modules/" }' me/composer.json) > me/composer.json
报错信息
fatal: [127.0.0.1]: FAILED! => {"changed": true, "cmd": ["cat", "<<<", "$(jq", "--indent", "4", ".autoload.\"psr-4\" += { \"Modules\\\": \"Modules/\" }", "me/composer.json)", ">", "me/composer.json"], "delta": "0:00:00.001982", "end": "2023-03-13 01:08:33.239162", "msg": "non-zero return code", "rc": 1, "start": "2023-03-13 01:08:33.237180", "stderr": "cat: unrecognized option '--indent'\nTry 'cat --help' for more information.", "stderr_lines": ["cat: unrecognized option '--indent'", "Try 'cat --help' for more information."], "stdout": "", "stdout_lines": []}
错误原因
command模块不会通过shell解析命令,会直接把重定向符号<<<、>和命令替换$(...)全部当成cat的参数,导致命令执行逻辑完全混乱。
可行解决方案
方案1:指定shell模块使用bash
修改shell模块配置,明确指定用bash执行命令,同时调整引号包裹避免YAML解析干扰:
- name: Add Modules PSR-4 autoload to composer.json shell: | cat <<< "$(jq --indent 4 '.autoload."psr-4" += { "Modules": "Modules/" }' me/composer.json)" > me/composer.json executable: /bin/bash
方案2:简化命令,避免here-string
直接让jq输出到临时文件再替换原文件(不能直接覆盖原文件,否则jq会读取空文件):
- name: Add Modules PSR-4 autoload to composer.json shell: | jq --indent 4 '.autoload."psr-4" += { "Modules": "Modules/" }' me/composer.json > temp.json && mv temp.json me/composer.json
方案3:使用Ansible JSON模块(最佳实践)
推荐用Ansible内置的community.general.json模块修改JSON文件,无需依赖jq,更符合配置管理理念:
- 先安装依赖集合:
ansible-galaxy collection install community.general
- 编写Playbook:
- name: Add Modules PSR-4 autoload to composer.json community.general.json: path: me/composer.json pretty: true pretty_print_width: 4 state: present key: autoload.psr-4.Modules value: Modules/
内容的提问来源于stack exchange,提问作者4n70wa
相关产品推荐
相关产品推荐

