Help us understand the problem. What is going on with this article?

Ansible: shellモジュールでシェルのヒアドキュメントを使用する2つの方法

問題

Ansibleのshellモジュールは、各行の先頭に空白文字を挿入して実行してしまう。その為、そのままシェルのヒアドキュメントを使用しようとすると、エラーとなったり意図しない動作となる可能性がある。

- shell: |
    cat << EOC
    foo
    bar
    EOC
  register: result

- debug:
    msg: "{{ result }}"

出力

TASK [shell] *******************************************************************************************************************
changed: [ansiblepush-centos-7]

TASK [debug] *******************************************************************************************************************
ok: [ansiblepush-centos-7] => {
    "msg": {
        "changed": true, 
        "cmd": "cat << 'EOC'\n foo\n bar\n EOC", 
...
        "failed": false, 
        "rc": 0, 
...
        "stderr_lines": [
            "/bin/sh: line 3: warning: here-document at line 0 delimited by end-of-file (wanted `EOC')"
        ], 
...
        "stdout_lines": [
            " foo", 
            " bar", 
            " EOC"
        ]
    }
}

ヒアドキュメントの区切り文字が見つからないとワーニングを出しつつも、このケースではタチ悪くエラーとならず、空白付き区切り文字を含め、スクリプトの最後までを出力してしまっている。後半に前半と対となるキーワードがあればエラーとなる。
result.cmdより、最後の区切り文字列を含め、各行とも先頭に空白文字が挿入され、区切り文字が見つかっていないことが判る。
タブ文字ではない為、<<-によっても対応できない。

対応方法1

shellモジュールのcmdパラメーターとして与えることで、先頭に空白が入ることを防ぎ、ヒアドキュメントを正常に動作させる事が可能。

- shell:
    cmd: |
      cat << EOC
      foo
      bar
      EOC
  register: result

- debug:
    msg: "{{ result.stdout }}"
TASK [shell] *******************************************************************************************************************
changed: [ansiblepush-centos-7]

TASK [debug] *******************************************************************************************************************
ok: [ansiblepush-centos-7] => {
    "msg": {
        "changed": true, 
        "cmd": "cat << 'EOC'\nfoo\nbar\nEOC\n", 
...
        "failed": false, 
        "rc": 0, 
...
        "stderr_lines": [], 
...
        "stdout_lines": [
            "foo", 
            "bar"
        ]
    }
}

参考:

対応方法2

<< ' EOC'の様に、指定する区切り文字列の先頭を空白文字とし、かつ終端で実際に指定する区切り文字列はその空白を除いた値とする。
この場合、ヒアドキュメント中では変数展開などは無効化されることに注意。(少なくともRubyではダブルクォートで囲った場合には展開を有効化、シングルクォートで囲った場合には無効化と、使い分け可能なのだが、シェルではどちらでも無効化の様子。)
ヒアドキュメントとしてはこれで動作できる様になるが、ヒアドキュメント中の先頭空白は入ったまま。それらも除きたければ例えば別途sedなどを用いる。

- shell: |
    cat << ' EOC'
      foo
      bar
      EOC
  register: result

# ヒアドキュメント中の先頭空白も除くなら、cat の行を sed 's/^ //' << ' EOC' などとする

- debug:
    msg: "{{ result }}"
TASK [shell] *******************************************************************************************************************
changed: [ansiblepush-centos-7]

TASK [debug] *******************************************************************************************************************
ok: [ansiblepush-centos-7] => {
    "msg": {
        "changed": true, 
        "cmd": "cat << ' EOC'\n foo\n bar\n EOC", 
...
...
        "failed": false, 
        "rc": 0, 
...
        "stderr_lines": [], 
...
        "stdout_lines": [
            " foo", 
            " bar"
        ]
    }
}

参考:

比較

制約の無い対応方法1で良いでしょう。

回避方法

代わりにscript moduleを使用する。

参考:

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away