[Ansible] 変数のテキスト出力をパディングする方法
はじめに
Ansibleでテキストを生成する際に、可変長の変数を使っていても出力をきれいに
そろえる方法を調べたためここに書き残しておく。
予備知識
変数の表示フォーマットはJinja2経由でPythonのメソッドを使うことで定義できる。
Template Designer Documentation — Jinja Documentation (3.1.x)
.format
を使う方法と%
を使う方法の2種類があるものの推奨は前者のようだ。
後者は以下のPythonのドキュメントからも分かるとおり古い表現方法らしい。
7. 入力と出力 — Python 3.10.6 ドキュメント
よって今回は.format
を使ってみる。
基本的な使い方
まずは桁ぞろえの前に基本的な使い方から学ぶ。公式ドキュメントはこのあたり。
string --- 一般的な文字列操作 — Python 3.10.6 ドキュメント
"{ 変数0の表示箇所 } { 変数1の表示箇所 }".format( 変数0,変数1 )
と使うようだ。
続いてフォーマットの指定については下記のあたりを参照。
string --- 一般的な文字列操作 — Python 3.10.6 ドキュメント
例えば数字の桁数を指定したい場合は
" { 0:4d } { 1:2d}".format( var_year,var_month )
のようにすればいいらしい。
以上を踏まえたPlaybook例がこちら。
--- - hosts: localhost gather_facts: false vars: date: - 2022 - 7 - 1 - 31 tasks: - name: print debug: msg: # 基本形。{}のなかの数字は、format()内に指定した変数群の幾つ目を使うかを指定するもの - "{{ 'date1... {0}/{1}/{2}'.format(date[0],date[1],date[2]) }}" # format()の変数を左から順に使う場合はこのように{}内の数字を省略可能 - "{{ 'date2... {}/{}/{}'.format(date[0],date[1],date[2]) }}" # このように同じ変数を複数回使いまわす場合は{}内に数字を入れたほうが簡略になる - "{{ 'date3... {0}/{1}/{2} - {0}/{1}/{3}'.format(date[0],date[1],date[2],date[3]) }}" - "{{ 'date4... {}/{}/{} - {}/{}/{}'.format(date[0],date[1],date[2],date[0],date[1],date[3]) }}" # フォーマットを指定したい場合、{}内の数字の後に:で区切って形式を定義する - "{{ 'date5... {0:04d}/{1:02d}/{2:02d}'.format(date[0],date[1],date[2]) }}" # フォーマットを指定しつつ、date2のように数字を省略した表記方法 - "{{ 'date6... {:04d}/{:02d}/{:02d}'.format(date[0],date[1],date[2]) }}"
実行結果
TASK [print] ***************************************************** ok: [localhost] => msg: - date1... 2022/7/1 - date2... 2022/7/1 - date3... 2022/7/1 - 2022/7/31 - date4... 2022/7/1 - 2022/7/31 - date5... 2022/07/01 - date6... 2022/07/01
発展形
先ほどの例では0で数字の桁を揃えたが、これでは使う場面が限定される。
ここからは0以外を使って、かつ変数の右側へのパディングも試してみる。
それには<
や>
を使う。例を見て頂くのが早い。
- hosts: localhost gather_facts: false vars: product: - name: apple value: 100 - name: carrot value: 1000 tasks: - name: print debug: msg: - | # まずは何も調整せず出力する例 {% for item in product %} {{ item.name }} {{ item.value }} {% endfor %} - | # <で変数右側へ半角スペースをパディング。10とすると、全体の文字数が10になるまで足される {% for item in product %} {{ '{:<10} {:<10}'.format(item.name,item.value) }} {% endfor %} - | # >で変数左側へ半角スペースをパディング {% for item in product %} {{ '{:>8} {:>6}'.format(item.name,item.value) }} {% endfor %} - | # >の後に文字を定義すると、その文字でパディングする。これは「0」でのパディング {% for item in product %} {{ '{:>8} {:>06}'.format(item.name,item.value) }} {% endfor %} - | # >の後に文字を定義すると、その文字でパディングする。これは「_」でのパディング {% for item in product %} {{ '{:_<10} {:<10}'.format(item.name,item.value) }} {% endfor %}
実行結果
TASK [print] ******************************************* ok: [localhost] => msg: - |- apple 100 carrot 1000 - |- apple 100 carrot 1000 - |2- apple 100 carrot 1000 - |2- apple 000100 carrot 001000 - |- apple_____ 100 carrot____ 1000
おまけ
引用したPythonのドキュメントを見るとわかるとおり他にも色々とできる。
例えば数値にカンマを入れたり、小数点以下の桁数を指定したり。
- hosts: localhost gather_facts: false tasks: - name: print debug: msg: - "{{ '{:.2f}'.format(1/3) }}" # 小数点以下を2桁にする - "{{ '{:,d}'.format(1000) }}" # 3桁ごとにカンマが入る表記
実行結果
TASK [print] ********************************************** ok: [localhost] => msg: - '0.33' - 1,000
感想
Ansibleを使ってても時折Pythonの知識は必要になるんだなぁ。