Ansible: shellモジュールでシェルのヒアドキュメントを使用する2つの方法
解消済み 2021/07追記
この問題はどこかのバージョンで対応が入って、少なくともansible 2.10.6では発生しない事を確認。
i.e. 行頭に勝手に空白が挿入されるということは無くなっている。
問題
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"
]
}
}
参考:
- ansible 1.7 passing an argument with newlines to the shell module eats newlines (edited title) #8512
- 入力と出力 | UNIX & Linux コマンド・シェルスクリプト リファレンス : ヒアドキュメント
比較
制約の無い対応方法1で良いでしょう。
回避方法
代わりにscript moduleを使用する。
参考:
Author And Source
この問題について(Ansible: shellモジュールでシェルのヒアドキュメントを使用する2つの方法), 我々は、より多くの情報をここで見つけました https://qiita.com/hiroyuki_onodera/items/e63d8d1fd640bb007a33著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .