Ansible Playbook中sed命令unterminated `s`错误的排查与修复
问题:Ansible中执行sed合并行命令报错
我有一个存储任务API代码及对应状态的文件,状态行位于API代码行的下一行,需要将每两行配对合并。在Shell中使用sed 'N;s/[\n]//'命令可正常运行,但在Ansible Playbook中执行时出现错误:sed: -e expression #1, char 4: unterminated s' command`。
相关信息
输入文件示例(api_file)
"id": "3b96db40-507e-4dd8-b2fd-e0e237fb928f", "enabled": true, ...
期望输出
"id": "3b96db40-507e-4dd8-b2fd-e0e237fb928f","enabled": true, ...
Playbook片段
- name: retrieve the IDs from the integration APIs shell: "cat api_file | sed 's/^ *//' > merged_api_file"
错误输出
TASK [retrieve the IDs from the integration APIs] ************************************************************************************************************************* Friday 07 July 2023 16:12:23 +0000 (0:00:00.805) 0:00:04.707 *********** fatal: [localhost]: FAILED! => {"changed": true, "cmd": "/usr/bin/cat /mnt/stl-server-actions/opsgenie/disable/opsgenie-integrations-2023-07-06-22-15-46.conf | egrep \"\"id\"|\"enabled\"\" | sed 's/^ *//' | sed -e 'N;s/\n//' > /mnt/stl-server-actions/opsgenie/disable/opsgenie-integrations-id-2023-07-06-22-15-46.conf", "delta": "0:00:00.005732", "end": "2023-07-07 16:12:23.294963", "msg": "non-zero return code", "rc": 1, "start": "2023-07-07 16:12:23.289231", "stderr": "sed: -e expression #1, char 4: unterminated `s' command", "stderr_lines": ["sed: -e expression #1, char 4: unterminated `s' command"], "stdout": "", "stdout_lines": []}
问题原因
Ansible的YAML解析器会处理字符串中的转义字符,导致sed命令里的\n被提前解析,实际传递给sed的命令变成了N;s//,缺少替换目标内容,因此触发“unterminated s' command”错误。同时从错误输出的cmd字段可见,egrep部分的引号也存在转义异常,但核心报错由sed`的换行符转义问题导致。
修正方案
方案1:用单引号包裹整个shell命令,避免YAML转义
将shell命令用单引号包裹,内部单引号用两个单引号转义(符合YAML单引号转义规则),确保命令原样传递给shell:
- name: retrieve the IDs from the integration APIs shell: 'cat api_file | sed ''s/^ *//'' | sed ''N;s/\n//'' > merged_api_file'
方案2:使用YAML块标量(|)定义命令,保留原始格式
通过|定义多行shell命令,无需额外转义即可保留原始命令格式:
- name: retrieve the IDs from the integration APIs shell: | cat api_file | sed 's/^ *//' | sed 'N;s/\n//' > merged_api_file
方案3:合并sed命令,减少管道(可选优化)
将两个sed命令合并为一个,提升执行效率:
- name: retrieve the IDs from the integration APIs shell: | sed -e 's/^ *//' -e 'N;s/\n//' api_file > merged_api_file
或更简洁的写法:
- name: retrieve the IDs from the integration APIs shell: 'sed ''s/^ *//;N;s/\n//'' api_file > merged_api_file'
验证
修正后的Playbook执行时,sed命令会正确接收N;s/\n//参数,实现每两行合并为一行并去除行首空格的效果,得到期望输出。
内容的提问来源于stack exchange,提问作者Philip Shangguan
相关产品推荐
相关产品推荐

