aws-vaultでexecするprofileとコマンドをzshの補完で選べるようにする
aws-vaultはAWSのprofileを指定して任意のコマンドを実行できます。
$ aws-vault exec my-profile -- aws s3 ls
この profile(my-profile
)の部分と 任意のコマンド(aws s3 ls
)の部分をTabキーで補完できるようにしました。
# サブコマンドの補完
$ aws-vault [Tab]
Completing subcommand
add clear exec help list login remove rotate
# profileの補完
$ aws-vault exec [Tab]
Completing profile
bar-role1 bar-role2 default foo-admin foo-readonly jonsmith
$ aws-vault exec f[Tab]
$ aws-vault exec foo-[Tab]
Completing profile
foo-admin foo-readonly
# コマンドの補完
$ aws-vault exec foo-readonly [Tab]
$ aws-vault exec foo-readonly -- [Tab]
Completing external command
.keepme ifconfig pnmtopng
2to3 ifnames pnmtopnm
2to3- ilbmtoppm pnmtops
2to3-2.7 img2webp pnmtorast
2to3-3.9 imgcmp pnmtorle
...
$ aws-vault exec foo-readonly -- aws e[Tab]
ebs ecr-public elastic-inference elb es
ec2 ecs elasticache elbv2 events
ec2-instance-connect efs elasticbeanstalk emr evidently
ecr eks elastictranscoder emr-containers
ソースコード
解説
補完の基本
補完スクリプト名
ファイルを用意し、
- 1行目に
#compdef コマンド名
-
補完スクリプト名
関数 - 最終行に
compdef 補完スクリプト名 コマンド名
を記述します。
補完スクリプトの中で、
_values
関数を使うと、第1引数が補完グループ名、第2引数以降が補完の候補として設定されます。
_arguments
関数を使うと、引数の位置に応じたアクションを定義できます。
サブコマンドの補完
_arguments
関数のアクションとして->(state-val)
と記述することでstate
変数に値がセットされます。
aws-vault
の第1引数を処理する際は$state
に"subcommand"
をセットし、定義したサブコマンドのリストを補完の候補とします。
#compdef aws-vault
_aws-vault() {
# サブコマンドのリスト(補完の候補)
local -a val
val=(help add list rotate exec clear remove login)
_arguments \
'1: :->subcommand' \ # 1つ目の引数処理時のstateを"subcommand"としてセット
case "$state" in
subcommand)
_values $state $val # stateが"subcommand"の際はサブコマンドのリストが候補とする
;;
esac
}
compdef _aws-vault aws-vault
profileの補完
第2引数以降はサブコマンドに何を選んだかに応じて以降の補完アクションを分岐させます。
第2引数以降の処理時、_arguments
関数で$state
に"args"
をセットします。
$state
が"args"
だった場合に、$words[1]
の値を確認することで第1引数がどれか確認できます。
exec
だった場合に、改めて_arguments
関数を用いて初めの引数処理時は__aws-vault-profile
関数が呼ばれるようにします。
__aws-vault-profile
関数ではprofileのリストをaws-vault ls
の結果から取得し、_value
関数によって補完の候補に設定しています。
_aws-vault() {
_arguments \
'1: :->subcommand' \ # 1つ目の引数処理時のstateを"subcommand"としてセット
'*:: :->args' \ # 以降の引数処理時のstateを"args"としてセット
case "$state" in
subcommand)
;;
args)
# サブコマンドに何を選んだかに応じて以降の補完アクションを分岐(今回はexecのみ定義)
case $words[1] in
exec)
_arguments \
'1: :__aws-vault-profile' \ # 1つ目の引数処理時に"__aws-vault-profile"関数を実行
'*:: :__aws-vault-exec-precommand' \
;;
esac
;;
esac
}
__aws-vault-profile() {
# profileのリストを`aws-vault ls`の結果から取得
local -a val
val=(`aws-vault ls | awk 'NR>2 {if ($1 != "-") print $1}'`)
# 取得したリストを補完の候補とする
_values 'profile' $val
}
コマンドの補完
profileの選択以降は__aws-vault-exec-precommand
関数で処理しています。
1つめの処理の際には区切り文字--
を補完するように__aws-vault-delimiter
関数を呼び出します。
それ以降はzshに定義された他の補完に全てを委任します。委任には_command
関数を使います。
(参考:zshに完全な自動補完を継承させるにはどうすればよいですか? - CODE Q&A)
__aws-vault-exec-command
関数内で_command
関数を呼び出します。
_aws-vault() {
_arguments \
'1: :->subcommand' \
'*:: :->args' \
case "$state" in
subcommand)
;;
args)
case $words[1] in
exec)
_arguments \
'1: :__aws-vault-profile' \
'*:: :__aws-vault-exec-precommand' \
;;
esac
;;
esac
}
__aws-vault-exec-precommand() {
_arguments \
'1: :__aws-vault-delimiter' \
'*:: :__aws-vault-exec-command' \
}
__aws-vault-delimiter() {
local -a val
val=(--)
_values 'EOC' $val
}
__aws-vault-exec-command() {
_command aws-vault
}
参考
参考にさせていただきました。
Discussion
参考にさせて頂きました、ありがとうございます 🙇
細かい点で恐縮ですが、_valuesが正確かと思います 🙇
ご指摘ありがとうございます!修正しました