如何在Ansible中编写多行Shell脚本

187

现在我正在使用一个Ansible中的shell脚本,如果它可以分成多行,它将更易读。

- name: iterate user groups
  shell: groupmod -o -g {{ item['guid'] }} {{ item['username'] }} ....more stuff to do
  with_items: "{{ users }}"

我不确定如何在Ansible shell模块中允许多行脚本


2
另外还可以考虑使用ansible的'script'命令并使用外部文件。 - Jason
7个回答

408

Ansible在playbooks中使用YAML语法。YAML具有许多块操作符:

  • >是一个折叠块操作符。也就是说,它通过空格将多行合并在一起。以下语法:

  • key: >
      This text
      has multiple
      lines
    

    将值This text has multiple lines\n分配给key

  • |字符是一个字面块操作符。这可能是你想要的多行shell脚本。以下语法:

  • key: |
      This text
      has multiple
      lines
    

    将值This text\nhas multiple\nlines\n分配给key

您可以将其用于像这样的多行shell脚本:

- name: iterate user groups
  shell: |
    groupmod -o -g {{ item['guid'] }} {{ item['username'] }} 
    do_some_stuff_here
    and_some_other_stuff
  with_items: "{{ users }}"

需要注意的一点是:Ansible对shell命令的参数进行了一些奇怪的操作,因此尽管上述方法通常能按预期工作,但以下方法则不行:

- shell: |
    cat <<EOF
    This is a test.
    EOF

实际上,Ansible会在文本前面添加空格,这意味着shell永远不会在一行的开头找到字符串EOF。您可以通过像这样使用cmd参数来避免Ansible的无用启发式方法:

- shell:
    cmd: |
      cat <<EOF
      This is a test.
      EOF

如果使用 ansible 而不是 ansible-playbook 会怎样? - Archon
使用 shell: > 实际上会导致 Ansible 插入换行符,因此这是不正确的。 - Philipp Ludwig
2
在这个答案中,我没有展示使用 shell: > 的例子,而且你的说法是错误的:Ansible 不知道你是否使用 ">|;它只知道在解析 YAML 后接收到的文本。> 引用操作符是一个折叠操作符,不会保留换行符。如果你看到了不同的行为,请随时提出问题,我很乐意帮忙查看。 - larsks
关于>下面行的缩进有一个小问题:它们必须以相同的缩进量缩进,才能正确地折叠(至少在Ansible中是这样)。我发表了一篇相关的答案。这可能就是@PhilippLudwig看到的问题? - JK Laiho

26

4
是的,但在Shell中,“>”符号具有非常特定的含义。我尝试过这个方法,但结果并非如预期。 - Subtubes
6
这就是为什么它只在第一行,而不是后续的行中。像我写的那样,在ansible 2.0上对我很有效,尽管在ansible 1.9.4上没有完整地输出ls结果。你使用的是哪个版本的Ansible? - Marcello Romani
@MarcelloRomani 它不适用于ansible 2.10.8。 - Philipp Ludwig

8

在EOF分隔符前添加一个空格可以避免出现cmd的问题:

- shell: |
    cat <<' EOF'
    This is a test.
    EOF

6

我更喜欢这种语法,因为它允许为shell设置配置参数:

---
- name: an example
  shell:
    cmd: |
      docker build -t current_dir .
      echo "Hello World"
      date

    chdir: /home/vagrant/

2
关于折叠运算符>的一个小提示,曾经让我困惑了一段时间:在使用Ansible时,缩进在它下面的行必须处于相同的缩进级别才能正确地进行折叠。
我正在转换一个现有的多行shell命令,该命令具有用于转义换行符的\行结尾,并将第一行以下的每一行缩进了两个空格。我使用了shell: >,删除了反斜杠并保留了现有的缩进。
换行符被保留了下来,我快要疯了,因为到处都说>应该将它们转换为空格。
请参见下面的示例:
# Converts into ls -la /tmp, as expected
- name: working shell command that folds newlines
  shell: >
    ls
    -la
    /tmp

# Tries to run -la and /tmp as their own commands
- name: failing shell command that does not fold newlines
  shell: >
    ls
      -la
      /tmp

希望这可以帮助到处于类似情况的人!

1
你可以使用 lineinfile 集合来追加文件,使用 create 属性来创建文件(如果不存在),并使用“|”符号来表示多行字符串。
- name: Add a line to a file if the file does not exist
  ansible.builtin.lineinfile:
    path: ~/.ssh/config
    line: |
      Host {{item.COMPONENT}} {{item.COMPONENT}}.{{ZONE}}
        HostName {{r53_var_one.resource_record_sets[0].resource_records[0].value}}
        User centos
        Port 22
        IdentityFile ~/.ssh/key.pem
        StrictHostKeyChecking no
    create: yes
    mode: '0600'

1
要了解在Ansible中如何使用多行,您可能希望测试此playbook以实际了解管道(LF->LF)和大于号(LF->空格)的含义。
- hosts: all,localhost
  tasks:
   - name: greather_than
     debug:
      msg: >
        a
        b
        c
   - name: pipe
     debug:
      msg: |
        a
        b
        c

这是以这种方式进行测试的。
# ansible-playbook test.yml
 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'


PLAY [all,localhost] ***************************************************************************

TASK [Gathering Facts] *************************************************************************
ok: [localhost]

TASK [greater_than] ****************************************************************************  
ok: [localhost] => {
    "msg": "a  b c\n"
}

TASK [pipe] ***********************************************************************************
ok: [localhost] => {
    "msg": "a \nb\nc\n"
}

 PLAY RECAP  ***********************************************************************************
 localhost                  : ok=3    changed=0    unreachable=0    failed=0       skipped=0    rescued=0    ignored=0

# 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接