【小ネタ】jqで特定の条件にマッチするかをbooleanで返すにはanyを使う

2015.12.09

タイトルで言いたいことは全て言い切りましたので、以下は補足です。

jqとは

JSONパーサであるjqでは、多様な表現を利用して柔軟にJSONを加工することができます。

AWS CLIのレスポンスフォーマットをjsonにしているので、jqで加工して必要な値を取得することが可能です。例えばEC2のインスタンスIDとNameタグ一覧を取得したい場合、以下のように記載すれば可能です。

aws ec2 describe-instances \
| jq -r '.Reservations[].Instances[] 
      | [.InstanceId, 
        (.Tags[] | select(.Key == "Name") | .Value)]'

[
  "i-xxxxxxxx",
  "SampleAP"
]
[
  "i-yyyyyyyy",
  "sampleDB"
]

ポイントは3行目です。タグ一覧からKeyがNameのものを探し、そのValueを取得しています。このあたりの話は弊社の過去のブログにもありますので参照下さい。

ユースケース

今回やりたかったのは、EC2インスタンスがAutoScaleで起動されたものかどうかをtrue/falseで返すことです。AutoScalingで起動したEC2インスタンスには、Keyがaws:autoscaling:groupNameのタグがついていますので、これを利用して判定できそうです。

ですが、上で利用したselectだと、存在するもののみを返すため、AutoscalingではないEC2にはこのタグが存在していないため、何も出力されません。

存在していればtrue、していなければfalseを返すために、jqにはany()という組み込み関数が用意されています。any()の引数に、判定用要素のexpressionを与えてあげれば、その要素が存在すればtrue、しなければfalseを返します。詳細はドキュメントを参照下さい。

なお、この機能はjqの最新版(1.5)からのみ利用可能です。jq1.4以前にもany()はありましたが、引数でexpressionを与えることができませんでした。

AutoScalingで起動されたEC2かどうかを判定するには、上のシェルを少し加工して、以下のようにすればよいでしょう。

$ aws ec2 describe-instances \
| jq -r '.Reservations[].Instances[] | 
        [.InstanceId,
        (.Tags[]| select(.Key == "Name")| .Value),
        (.Tags | any(.Key == "aws:autoscaling:groupName"))]'

[
  "i-xxxxxxxx",
  "SampleAP",
  true
]
[
  "i-yyyyyyyy",
  "sampleDB",
  false
]

5行目が新しく足された表現になります。そして出力項目がひとつ増えたのがわかるかと思います。AutoScalingで起動されたものの場合、3番目の項目がtrueとなります。

もしかしたらどこかで役立つかもしれません。ご活用下さい。