🎄

ansibleで空配列の定義と値の入れ込みを1つのタスク内で処理するtips

に公開

そうしたい時もあると思います。


この記事は SKIYAKI Tech Blog Advent Calendar 2025 の3日目の記事になります。


空配列の定義と値の入れ込みに2タスクも使いたくない

ループで回した値を定義した配列に順次入れ込んでいきたい場合にどうしているでしょうか。
私は以前こんな感じにしていました。

空配列定義(1タスク), 変数セット(1タスク)
- name: define empty array
  ansible.builtin.set_fact:
    array: []

- name: set variable in array
  ansible.builtin.set_fact:
    array: "{{ array + [item] }}"
  loop:
  - "a"
  - "b"

最初のタスク define empty array で空配列 array を定義して、次のタスクで実際の値を入れていく形です。
これで set variable in array の実行後、 array の中身は ["a", "b"] となります。
この書き方でも別に良いのです。良いのですが、なんだか冗長ですね。
できれば空配列の定義と、それに値を入れ込む処理は1タスクでいい感じに処理したい…!

1タスクで完結させる

そんなわけで、調べたり検証したりしたところ、以下のように書けば1タスクで完結できるぞ…!ということがわかりました。

空配列定義(初期化)+変数セット
- name: define array and set variable
  ansible.builtin.set_fact:
    array: "{{ array | default([]) + [item] }}"
  loop:
  - "a"
  - "b"

array: の定義部分ですが、ここに default フィルターを使うことで、空配列 [] が設定されます。
この default フィルターは、変数が定義されていない場合にしか適用されないため、初回以外は無視されます。
結果、 default フィルターで空配列が array に設定された後、ループで回した値が入れられていくため、一番上に書いた2タスク分の処理と同じとなる…といった感じです。
便利ですね。

これをどう使うかというと register で取得したタスクの結果ですとか、自分で定義した vars の配列をループさせて必要な情報だけ取り出したい時とか、そういう時に使ったりします。

変数定義に1タスク使うのもなんだかなではあるのでこういう形で短縮できると見通しも良くなっていいんじゃないでしょうか。

この方法だと不備が発生する場合

とはいえこれがどんなplaybookにでも使えるかと言われると、それは場合によると思います。
例えばこのタスクに when 句があって、条件によっては処理されない時があるのに、後続処理では定義した array を絶対使う…といったplaybookだと、空配列の定義と値の入れ込み処理は分けた方が良さそうです。

不備が発生する例
# 例えばwhen句があって、 is_prd が false である場合
- name: define array and set variable
  ansible.builtin.set_fact:
    array: "{{ array | default([]) + [item] }}"
  loop:
  - "a"
  - "b"
  when:
  - is_prd # (false)

# 上のタスクはis_prdがfalseとなりタスクの実行自体がskipされてしまうため、
# array が存在しないことになり、この output array タスクは失敗する
- name: output array
  ansible.builtin.debug:
    msg: "{{ item }}"
  loop: "{{ array }}"

最後に

この書き方は確かStack OverFlowに記載されていて、「なるほど便利だなー」で真似していたのですが、肝心の元URLを失念…。
探しても出てこずで、もしかしたらその質問自体が消えてしまったのかも…。
参考URLとして載せたいのだけど、どう調べたら出てくるでしょう…。

SKIYAKI Tech Blog

Discussion