🌸

jqコマンドで絞り込んだ結果の最初の要素を取り出す方法

2021/03/24に公開

はじめに

コマンドラインでAPIを実行し、結果から必要な部分をjqコマンドで取得するということがよくあると思います。
今回、jqコマンドで簡単にできそうだけど、意外とハマったことに関して書こうと思います。

やりたかったこと

今回実現したかったことは、「AWS CLIを使って、ある特定の名前の、実行中のインスタンスのうちの一台の、プライベートIPアドレスを取得する」です。

まずは正解

まずは、最終的に辿り着いたコマンドを紹介します。

aws ec2 describe-instances --filters "Name=tag:Name,Values=XXXXX" \
| jq -r ['.Reservations[].Instances[0] | select(.State.Name == "running").PrivateIpAddress'][0]

前半部分では、AWS CLIを利用し、インスタンス名が XXXXX であるEC2インスタンスを取得します。
ここまではとても簡単です。

ここから情報を絞り込んでいく訳ですが、まずは、「実行中のインスタンス」を絞り込みます。
これは、コマンドの次の部分で行っています。

'.Reservations[].Instances[0] | select(.State.Name == "running")

AWSのAPIから返還された情報は、Reservationsという配列の中に、Instancesという配列が含んでいます。
一つ一つのインスタンスの情報は、Reservationsの要素として格納されています(この辺りの詳しい情報は、公式ドキュメントを参考にしていただければと思います)。
なので、取得した全てのインスタンスの情報うち、Instances配列の0番目の要素の、State要素内のNameの値がrunningのものを、selectで抽出しています。

次に、実行中のインスタンスのプライベートIPアドレスを取得します。
これは簡単で、先程の絞り込みの後ろに、プライベートIPアドレスを格納しているキー PrivateIpAddress をくっつけてあげれば良く、次のようになります。

'.Reservations[].Instances[0] | select(.State.Name == "running").PrivateIpAddress'

ここで、実行中のインスタンスが複数の場合は、それらのプライベートIPアドレスも複数になる訳です。
そのうちの一つを取得するには、次のように、一度、プライベートIPアドレスをリストに入れてあげて、その0番目の要素を取得します。

jq -r ['.Reservations[].Instances[0] | select(.State.Name == "running").PrivateIpAddress'][0]

どこでハマったか

と、一つ一つ説明していくと、当たり前のように感じられると思います
しかし、「複数抽出できるプライベートIPアドレスのうち、一つを取得する」という処理の実現に手間取りました。
例えば、次のようなコマンドでは、エラーが発生してしまいます。

aws ec2 describe-instances --filters "Name=tag:Name,Values=chatbot-yosh-faqsearch-es7" | jq -r '.Reservations[].Instances[0].PrivateIpAddress[0]'

いくらググってみても、自分が欲しい情報に辿り着けず、また、そもそもこの問題をどのようにググればいいものか、とても悩みました。
最終的には、なんとかこのページに辿り着き、やりたいことを実現するコマンドを書くことができました。

おまけ

この記事を書くために、もう少し調べてみました。
結局のところ、これが一番簡単です。

aws ec2 describe-instances \
    --filters "Name=tag:Name,Values=XXXXX" "Name=instance-state-name,Values=running" \
    --query Reservations[0].Instances[0].PrivateIpAddress \
    --output text

Discussion