◆ 直接 ssh-ident 自体で使う方法は想定されてない
◆ alias やシンボリックリンクやリネームや環境変数などの設定が必要
◆ alias の場合 カレントディレクトリに ssh-ident があるとうまく動かない
◆ BINARY_SSH で内部で実行するプログラムのパスを指定するのが良さそう

ssh-ident を実行すると

ssh-ident を最初に使ったときに

ssh-ident found 'ssh-ident' as the next command to run.
Based on argv[0] (/home/user/ssh-ident), it seems like this will create a
loop.

Please use BINARY_SSH, BINARY_DIR, or change the way
ssh-ident is invoked (eg, a different argv[0]) to make
it work correctly.

というエラーになりました

変に苦労したのですが ssh-ident では内部的に使う ssh コマンドを自動で検出機能があります
検出できたものが ssh-ident 自身だとそれを呼び出したらループするので 自身かを調べて ssh-ident 自身と判定されるとエラーが表示されます

コード的には 下の 2 つの変数が等しければこのエラーになります

binary_path = os.path.realpath(
distutils.spawn.find_executable(config.Get("BINARY_SSH")))
ssh_ident_path = os.path.realpath(
distutils.spawn.find_executable(argv[0]))

BINARY_SSH や BINARY_DIR の環境変数で直接指定できるので 面倒なら .bashrc などに書いておくと ssh-ident の実行方法の影響うけないので楽に済みます

binary_path と ssh_ident_path

binary_path

binary_path というのが本物の ssh コマンドがあるパスを表しています
ssh-ident は鍵管理が目的なので 他の ssh を使うコマンド scp などでも使えます
その場合は binary_path が scp のパスになります

いろいろな ssh ツールとして使えるため ssh-ident は自身が実行されたコマンド名を元に 実行するバイナリファイルを探します
一見便利ですが この処理のために 実行方法が制限されて実行方法によってはエラーになります

シンボリックリンクやリネームで ssh や scp という名前にすれば楽に 実行するコマンドを指定できそうですが自分自身が検出されないようにする必要があります

普通にやるとそのコマンド名で呼び出せてるわけですから ssh-ident のほうが検出されます

alias

とりあえず素直に使い方通りにやることにしました
やることは

All you have to do is modify your .bashrc to have:

alias ssh='/path/to/ssh-ident'

ssh に ssh-ident への alias を設定するだけでいいようです

alias だとシンボリックリンクと違って実行するコマンドは本来の名前なので プログラム中で認識される名前は ssh-ident です
とりあえずやってみたのですが変わらず ssh-ident 自体が検出されてループになりました

いろいろ試してみると ssh-ident のあるフォルダで実行するとダメでした
ホームディレクトリに ssh-ident をダウンロードしていたので ssh の alias にホームディレクトリの ssh-ident を指定して ホームディレクトリで実行したらダメでした
ssh-ident を /opt/ssh-ident/ssh-ident に移動して alias もそっちに移動したら問題なくなりました
ただ カレントディレクトリを /opt/ssh-ident に移動したらダメでした

ssh-ident は普段行かない場所に配置すべきですね

検出の仕組み

ホームディレクトリに ssh-ident を置いたときと /opt/ssh-ident に置いたときの binary_path と ssh_ident_path を調べました

どちらも

os.path.realpath(distutils.spawn.find_executable(path))

の方法で取得しているので 最終的な値と find_executable の結果と元の path の部分のそれぞれをスペース区切りで表示しています

ホームディレクトリ
binary_path:
/home/user/ssh-ident ssh-ident ssh-ident
ssh_ident_path:
/home/user/ssh-ident /home/user/ssh-ident /home/user/ssh-ident

/opt/ssh-ident
binary_path:
/usr/bin/ssh /usr/bin/ssh /usr/bin/ssh
ssh_ident_path:
/opt/ssh-ident/ssh-ident /opt/ssh-ident/ssh-ident /opt/ssh-ident/ssh-ident

ホームディレクトリの方では path の部分が ssh-ident になっているので realpath で今のフォルダの ssh-ident に変換された結果 ssh-ident と同じパスになります
/opt/ssh-ident の方では /usr/bin/ssh なので最初から本当の ssh が取得できてます

環境変数を指定しない場合に

config.Get("BINARY_SSH")

で取得できるものがどうやって作られるかを調べると下のコードの binary_path が設定されていました

binary_path = distutils.spawn.find_executable(binary_name, search_path)
if not binary_path:
# Nothing found. Try to find something named 'ssh'.
binary_path = distutils.spawn.find_executable('ssh')

/opt/ssh-ident の方では if の中に入って ssh で検索がされた結果 /usr/bin/ssh が取得できてるようです
binary_name は実行したファイル名なのでどちらも ssh-ident になっています
それを

distutils.spawn.find_executable(binary_name, search_path)

の処理で検索した結果 ホームディレクトリでは見つかって /opt/ssh-ident では見つからず None になっています
search_path にホームディレクトリが入っていたのかと思いましたが 見てみても入ってませんでした

distutils.spawn.find_executable の探す対象が暗黙的に カレントディレクトリを含むようです
見つからないファイルを探したあとにそのファイル名があるディレクトリに os.chdir で移動してもう一度実行すると見つかりました
find_executable がカレントディレクトリを含むという仕様を把握できてないだけな気もしますが なにか別の理由があって仕方なくなのかもしれません

sudo 風な使い方でよかったのに

ssh を置き換えるような使い方になってますが sudo などのようにコマンドの引数に実行するものを書いて ssh-ident 自体は ssh-ident として alias やシンボリックリンクは使わず使えるのが良かったと思います

ssh-ident ssh user@server-name

という感じです
変に ssh や scp をそのまま置き換えれるようにしようとしたせいで扱いづらくなってる気がします

そこまで長くないプログラムな上に これとか鍵ロードの問題でほとんどソースは目を通したので こういう使い方ができるように作り変えようかな……

とりあえず ssh-ident 自体を使う場合は 余計なトラブルをなくすためにも BINARY_SSH を書いておいたほうが良さそうです