システムへのログイン時に自動的にbash readlineをviモードに設定する方法は?


9

私のチームは何千ものLinux / Unixマシンを担当しているため、当然、rootアカウントは管理者間で「共有」されます。私はviモードを好み、他はemacsモードを好みます。

他の全員にviモードを使用するように強制せずに、どのマシンにSSHログインしたときに、bashのreadlineをviモードに設定するにはどうすればよいですか?

本質的には、set -o vi実際に毎回入力する必要がなく、他の人にそれを強制することなく、ログイン後の効果を持ちたいと思います(emacsモードは私に不快であるのと同じように、viモードはそれらに不快です)。

誰もがsudoで自分のアカウントを使用して特権コマンドを実行する場合、これは問題にならないことはわかっていますが、私の制御外の状況により、これは残念ながらオプションではありません。


1
それは簡単ではありません。1つの方法は、sshdのログファイルを解析して、ログインに使用されたキーを確認することです。クライアント側のソリューションを望んでいました。たとえば、ローカルのreadline構成をリモート側に渡す方法などです。set -o viシェルを制御する前に静かに実行される暗いOpenSSHの魔法。
Patrick

1
おそらく、sshがサーバーに入るクライアントでExpectスクリプトを使用し、set -o viコマンドを送信してから、インタラクティブモードに切り替えることができます。
Barmar 2017年

1
少なくともOpenSSH sshdはいくつかの環境変数を設定します。これは、相手が誰であるかを判断するのに役立つ場合があります。たとえばSSH_CLIENT、接続IPアドレス(およびクライアントの送信/受信ポート)が含まれています。これをいじくり回すと、あなただけのために~/.bashrc何かができるようになるかもしれませ
サミレイン2017年

1
バウンティは、「クライアント側のソリューション」を探していると言っています-それは何ですか?Unixホストでssh?パテ?ハチドリ?Java SSH?Cygwin?
ジェフシャラー

1
あなたは数万台のマシンについて言及しています。1台のマシンから始めて、これらのマシンに到達したいですか、それともマシン間でviモードを実行しているマシン間でホップできるようにしたいですか?
イカルス2017

回答:


3

これは愚かな方法ですが、これは実際には公開鍵認証でのみうまく機能します。

まず、ローカルマシンにインストールさncれていることを確認します。

次に、まだローカルマシンで、スクリプトを作成し(私はそれを呼び出しますconnect-to-server)、${PATH}知っている場所に置きます*:

#!/bin/sh
# connect-to-server
ssh -q server-hostname "touch .yourname" </dev/null >/dev/null 2>&1
nc server-hostname 22

次に、.bashrcリモートシステムのを変更して、どこかに含めるようにします。

# partial .bashrc
if [ -f "${HOME}/.yourname" ]; then
  rm "${HOME}/.yourname"
  set -o vi
fi

最後に、ローカルマシンに戻り、編集~/.ssh/configして追加します。

# partial ssh config
Host serverNickname
  Hostname server-hostname
  ProxyCommand connect-to-server

このアプローチの欠点(そしてなぜ私がそれをばかげていると思うのか):

  • 実際のプロキシコマンドが必要な場合は、さらに複雑になります。
  • 同時に他の誰かがログインした場合、.yournameファイルがまだ削除されていない可能性がありますset -o vi。その場合、それらも取得されます。
  • 最も重要なことはssh serverNickname commandcommand実行する場合は実行.bashrcされ.yournameますが、(ソースが提供されることはないため)ファイルは残るため、疑似プロキシを使用しないssh構成に2番目のエイリアスがあることは礼儀です。

実際、このアプローチの唯一の利点は、sshコマンドに引数を追加する必要がないことです。


*リモートシステムで何も変更する必要がない場合は、一時を作成する別の疑似プロキシを次に示します.bashrc

#!/bin/sh
# connect-to-server
ssh -q server-hostname 'ln .bashrc .bashrc.real; cat .bashrc.real <(printf "set -o vi; ln -f .bashrc.real .bashrc\n") >.bashrc.yourname; ln -f .bashrc.yourname .bashrc' </dev/null >/dev/null 2>&1
nc server-hostname 22

これには他の方法と同じ欠点がありsshます。そのため、疑似プロキシを呼び出さない構成に2番目のエイリアスが必要です。


とてもクリエイティブ。提案ありがとうございます。私はすでにProxyCommandを広範囲に使用しています(一部のネットワーク/ホストは到達するために5以上のホップを必要とします)。これはすぐに構成の悪夢になります。編集:私があなたの答えに最も近いと思うすべての答えを見てください。
Patrick

4

私は行きます:

ssh server -t "bash --login -o vi"

しかし、それはあなたが管理者である場合、よりクリーンなものを試すことができます。たとえばSendEnv、クライアント側でssh オプションを使用AcceptEnvして特定の変数を送信し、sshd構成(サーバー側)でそれを受け入れ、これに基づいて、ルートの.bashrcファイルを変更し、変数の値に従って動作を調整できます。

これはsshd、すべてのホストとそのホストの構成を変更することを意味します.bashrc。ただし、「スタンドアロン」の方法とは異なります...


3

簡単なクライアント側ソリューションの場合:

alias connect='ssh -t root@server "bash -o vi"'

ルートのシェル初期化スクリプトが明示的にを使用set -o emacsまたは設定EDITORしているemacs場合、またはルートの.initrcファイルがemacsキーバインディングを呼び出している場合、これは失敗します。

この回答の残りの部分は、サーバー側のソリューションに関するものです。


これはssh、マシンにアクセスしてから使用すると機能しますsudo -i

あなたのために/root/.bashrc

if [[ -n "$SUDO_USER" ]] && [[ -f /root/.bashrc-"$SUDO_USER" ]]; then
  source /root/.bashrc-"$SUDO_USER"
fi

これにより、bashrcという名前の個人用ファイルを作成して、/root/.bashrc-patrickなどの好きなことを何でもできるようになりset -o viます。

これを、以下に応じてそのrcファイルを取得するためのやや素朴なアプローチと組み合わせる$SSH_CLIENT

if [[ -n "$SUDO_USER" ]]; then
  person="$SUDO_USER"
elif [[ -n "$SSH_CLIENT" ]]; then

  case "$SSH_CLIENT" in
    192.168.216.100*)  person="joe" ;;
    192.168.216.120*)  person="patrick" ;;
    192.168.216.150*)  person="lindsey" ;;
  esac

fi

if [[ -n "$person" ]] && [[ -f /root/.bashrc-"$person" ]]; then
  source /root/.bashrc-"$person"
fi

これは明らかに、常に同じIPアドレスから接続している場合にのみ機能します...

SSHエージェントをサーバーに転送する場合に機能する、使用している特定のSSHキーのコメントフィールドを使用する別のアプローチ:

ssh_comment="$( ssh-add -L | grep -f /root/.ssh/authorized_keys | awk '{ print $NF '} | head -n 1 )"

これにより、サーバーへの接続に使用したキーのコメントフィールドが選択されます。これhead -n 1は、authorized_keysファイルにいくつかのキーが含まれている場合に備えてあります。

次に、を使用$ssh_commentしてソースにrcファイルを選択するか、$SUDO_USER上記のアプローチと直接($ssh_commentパス名の場合はコメントをクリーンアップする必要がある場合があります)、またはアプローチcaseと同じようにステートメントを使用し$SSH_CLIENTます。


マッチングSSH_CLIENTSUDO_USERは、私が現在使用しているものですが、サーバー側の変更が必要であり、特に信頼性は高くありません。純粋なクライアント側のソリューションを望んでいました。提案をありがとうございました。
Patrick

3

サーバー側で変更せずにそれを本当に実行したい場合は、次のいずれかを実行します。

1)のようなものを実行します

$ ssh user@host -t 'bash -l -o vi' 

そのことについてのドキュメントはあまり明確ではないと思いますが、-o option言及されていて機能しているようです。

2)expectを使用します。

expectスクリプト:

$ cat bashsetup.expect
#!/usr/bin/expect -f 

set user [lindex $argv 0];
set host [lindex $argv 1];

spawn ssh -l $user $host
expect "$ "
send "set -o vi\n"
interact

実行可能にして実行します。

$ ./bashsetup.expect user testhost
spawn ssh -l user testhost
[motd, blahblah...]
user@testhost ~$ set -o vi
user@testhost ~$ 

これは、パスワードを入力せずに(リモートホストまたはキー用に)ログインできることを前提としています。そうでない場合、expectスクリプトはそれを考慮する必要があります。しかし、多くのマシンでは、すでにそれを持っている可能性があります。また、私は期待あなたのプロンプトに従った編集、ドル記号とスペースのために:"# "おそらく。

ただし、プロンプトの前に印刷されたものに同じ文字が含まれている場合は、予期される文字列により具体的なものを含める必要があります。

また、そのスクリプトはに追加の引数を与えることをサポートしていませんssh。実行するコマンドを明示的に指定する場合は、おそらくviモードは必要ありませんが、たとえばポートトンネリングが必要な場合は、問題になる可能性があります。


しかし、いずれにしても、これは個別のアカウント(sudoまたは単純に古いUID 0)を持つターゲットシステムで解決する必要があると私は本当に思います。パーソナライズされた構成は、他の多くの場合にも役立ちます。一般に、設定する一連の構成ファイルと環境変数があります。(管理者がの値$EDITORや内容などについて同意しない可能性があることを考慮してくださいvirc。)

また、個別のアカウントを使用すると、ユーザーを簡単に削除できます。

すべてのホストでファイルを同期する方法でも、ssh -t user@host 'patricks_shell.sh'またはのようなものでログインできるようにすることで、これを簡単に解決できますssh -t user@host 'bash --rcfile patrick.rc'


expectを使用することを考えましたが、あなたの質問ですでに指摘したように、問題はプロンプトを開始するためのユニークなものと一致していますinteract。これは存在しません。motds/プロファイルからの出力と同様に、プロンプトは異なる場合があります。しかし提案をありがとう。
Patrick

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.