如何在Ansible中正确编写awk命令?解决模板语法报错问题
问题描述
终端中可正常运行的awk命令如下:
awk '/java/ {print "PID is:" $2" Process Dump is: " $0}' <(ps -ef | grep -v grep)
执行后输出示例:
PID is:515 Process Dump is: wladmin 515 506 0 Nov03 ? 01:11:39 /web/jdk-18.0.1.1/bin/java -jar remoting.jar -workDir /web/jenkinsprod -jar-cache /web/jenkinsprod/remoting/jarCache PID is:22145 Process Dump is: wladmin 22145 22140 0 Nov04 ? 00:54:18 /web/jdk-18.0.1.1/bin/java -Djava.io.tmpdir=/web/jenkins_windows/tmp -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -jar remoting.jar -workDir /web/jenkins_windows -jar-cache /web/jenkins_windows/remoting/jarCache PID is:32703 Process Dump is: wladmin 32703 32699 0 Nov03 ? 01:10:34 /web/jdk-18.0.1.1/bin/java -Djava.io.tmpdir=/web/jenkins/tmp -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -jar remoting.jar -workDir /web/jenkins -jar-cache /web/jenkins/remoting/jarCache
尝试将该命令整合到Ansible中,生成包含java和ssh两个匹配项的命令列表,编写的Playbook如下:
--- - name: Concant and Print variable gather_facts: false hosts: localhost tasks: - name: Test set_fact: process_dump: "{{ process_dump | default([]) + ['awk \'/\" ~ item ~ \"/ {print \"PID is:\" $2\"\nProcess Dump is:\t\" $0}\' <(ps -ef | grep -v grep)'] }}" loop: - 'java' - 'ssh' - debug: msg: "{{ item }}" loop: "{{ process_dump }}" - command: "{{ item }}" loop: "{{ process_dump }}"
执行时触发模板错误:
TASK [Test] **************************************************************************************************************************************************************************************************** fatal: [localhost]: FAILED! => {"msg": "template error while templating string: expected token ':', got 'string'. String: {{ process_dump | default([]) + ['awk '/' ~ item ~ '/ {print \"PID is:\" $2\"\nProcess Dump is:\t\" $0}' <(ps -ef | grep -v grep)'] }}"}
错误原因
- Jinja2模板转义冲突:
set_fact中的字符串拼接逻辑混乱,单双引号转义错误,导致模板引擎无法正确识别语法边界,误判字符串结束位置。 command模块不支持shell特性:原命令使用了<()进程替换(bash专属特性),但command模块直接执行命令,不经过shell解析,无法识别该语法。- 复杂拼接易出错:直接在Jinja2表达式中拼接带特殊字符的命令,可读性差且极易出现转义失误。
正确的Ansible配置
提供两种可行的修正方案:
方案一:直接在任务中执行(简洁版)
--- - name: Collect process dumps gather_facts: false hosts: localhost tasks: - name: Execute process check commands shell: | awk '/{{ item }}/ {print "PID is:" $2"\nProcess Dump is:\t" $0}' <(ps -ef | grep -v grep) loop: - 'java' - 'ssh' register: process_dump_results - name: Print process dumps debug: msg: "{{ item.stdout }}" loop: "{{ process_dump_results.results }}"
方案二:提前构造命令列表(可复用版)
--- - name: Collect process dumps gather_facts: false hosts: localhost tasks: - name: Build command list set_fact: process_dump_commands: "{{ process_dump_commands | default([]) + [command] }}" vars: command: "awk '/{{ item }}/ {print \"PID is:\" $2\"\\nProcess Dump is:\\t\" $0}' <(ps -ef | grep -v grep)" loop: - 'java' - 'ssh' - name: Show commands debug: msg: "{{ item }}" loop: "{{ process_dump_commands }}" - name: Execute commands shell: "{{ item }}" loop: "{{ process_dump_commands }}" register: process_dump_results - name: Print results debug: msg: "{{ item.stdout }}" loop: "{{ process_dump_results.results }}"
修改说明
- 替换
command模块为shell模块,支持bash的进程替换特性。 - 用Jinja2变量
{{ item }}直接注入匹配项,规避复杂的字符串拼接转义。 - 用
register捕获命令执行结果,方便后续输出或二次处理。 - 将换行符
\n转义为\\n、制表符\t转义为\\t,确保Jinja2解析后能正确传递给shell。
内容的提问来源于stack exchange,提问作者Ashar
相关产品推荐
相关产品推荐

