はじめに
Ansible で、リストの中の各要素に対して一律でなにかの処理をして、別の要素を生成したいときがあります、
Python の内包表記でリストを生成するイメージです。
全く同じというわけではないのですが、map
フィルターを利用すると近いことが少しできることを知りました。
少し説明しにくいので、 Python で書く場合と比較していくつかサンプルをご紹介します。
- 動作確認環境
- Ansible 2.9.9
- Jinja2 2.11.2
各要素に文字列を結合する
Python
Python だとこのイメージ。
>>> ['Hello ' + i for i in ['funa', 'kingyo', 'same']] ['Hello funa', 'Hello kingyo', 'Hello same']
Ansible
Ansible だとこのような感じです。
もっとシンプルにする方法があると良いのですが、正規表現を使う方法しか思いつきませんでした。
- name: naihou debug: msg: "{{ ['funa', 'kingyo', 'same'] | map('regex_replace', '^(.+)$', 'Hello \\1') | list }}"
- 結果
ok: [localhost] => { "msg": [ "Hello funa", "Hello kingyo", "Hello same" ] }
なお、map
フィルターに regex_replace
を渡せることは以下の記事で知りました。ありがとうございます。
Jinja2のmapフィルタの中身に引数が必要なフィルタを指定する - Qiita
各要素を大文字にする
Python
Python だとこのイメージ。
>>> [i.upper() for i in ['funa', 'kingyo', 'same']] ['FUNA', 'KINGYO', 'SAME']
Ansible
Ansible だとこのような感じです。upper
フィルターを併用します。
- name: naihou debug: msg: "{{ ['funa', 'kingyo', 'same'] | map('upper') | list }}"
- 結果
ok: [localhost] => { "msg": [ "FUNA", "KINGYO", "SAME" ] }
各要素を int にキャストする
Python
Python だとこのイメージ。
>>> [int(i) for i in ['111', '222', '333']] [111, 222, 333]
Ansible
Ansible だとこのような感じです。
- name: naihou debug: msg: "{{ ['111', '222', '333'] | map('int') | list }}"
- 結果
ok: [localhost] => { "msg": [ 111, 222, 333 ] }
おわりに
リスト loop
で回しながら、処理して set_fact
する方法でもできますが(こちらのほうが柔軟)、一つのタスクするまでもないときには、このように内包表記チックにやるのもいいと思います。
なお、Jinja2 として、内包表記そのものはサポートしていないとドキュメントに明記されています。