首页 > 解决方案 > Ansible:如何使用特殊字符运行多步 shell 命令

问题描述

在我的剧本下,我想运行一个 shell 命令,如下所示:

for STACK in stackone  stacktwo;do  docker stack ps  --format "table {{.ID}}\t{{.Name}}\t{{.CurrentState}}\t{{.Error}}\t{{.Node}}" $STACK | (read -r; printf "%s\n" "$REPLY"; sort -k 2|grep srcd |grep -v Shutdown ); done; 

如您所见,我的shell命令非常复杂,所以当我像这样运行它时,它总是会抛出语法错误。

 - name : Check running services
   shell: for STACK in stackone    srcd-pilote;do  docker stack ps  --format "table {{.ID}}\t{{.Name}}\t{{.CurrentState}}\t{{.Error}}\t{{.Node}}" $STACK | (read -r; printf "%s\n" "$REPLY"; sort -k 2|grep srcd |grep -v Shutdown ); done; 
   register: result

我看到有许多字符需要作为字符串传递,例如{{.Name}}|grep ...

所以我试过这个:

- name : Check running services
  shell: "for STACK in srcd-current  stacktwo;do  docker stack ps  --format 'table {{'"{{.ID}}"'}}\t{{'"{{.Name}}"'}}\t{{'"{{.CurrentState}}"'}}\t{{'"{{.Error}}"'}}\t{{'"{{.Node}}"'}}' $STACK | (read -r; printf '%s\n' '$REPLY'; sort -k 2'"{{|}}"'grep srcd '"{{|}}"'grep -v Shutdown ); done; "
  register: result

但它仍然失败。

建议??

标签: ansiblejinja2ansible-2.xansible-template

解决方案


我不得不for在我的一项 ansible 任务中使用 shell 循环。我使用文字块标量 ' |' 来做到这一点。尝试这样的事情:

- name : Check running services
  shell: |
    for STACK in stackone srcd-pilote;do
      docker stack ps  --format "table {{ '{{' }}.ID{{ '}}' }}\t{{ '{{' }}.Name{{ '}}' }}\t{{ '{{' }}.CurrentState{{ '}}' }}\t{{ '{{' }}.Error{{ '}}' }}\t{{ '{{' }}.Node{{ '}}' }}" $STACK | (read -r; printf "%s\n" "$REPLY"; sort -k 2|grep srcd |grep -v Shutdown ); 
    done;

更多关于标量的文档可以在Ansible 文档中找到 YAML 语法

您还应该使用{{and}}从 jinja2 中转义{{ '{{' }}and {{ '}}' }}

注意 1:这是一个很好的 sed 命令:

s/{{\([^}]*\)}}/{{ '{{' }}\1{{ '}}' }}/g

注意 2:您应该查看命令以将其拆分为几行以提高可读性(\在行尾或使用>标量)。

Ansible-Lint 规则建议行短于 160 个字符(规则 E204)。


推荐阅读