jqコマンドで絞り込んだ結果の最初の要素を取り出す方法
はじめに
コマンドラインで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