Comment mettre bash readline en mode vi automatiquement lors de la connection à un système?

Mon équipe est responsable de milliers de machines Linux / Unix, donc naturellement le count root est "partagé" entre les administrateurs. Je préfère le mode vi, d'autres préfèrent le mode emacs.

Comment puis-je définir le mode readline en mode vi sur connection SSH à n'importe quelle machine, sans forcer tous les autres à utiliser le mode vi aussi?

Essentiellement voudrait avoir l'effet de set -o vi après la connection sans avoir à taper à chaque fois, et sans forcer sur tout le monde (autant que le mode emacs m'ennuie, le mode vi est ennuyeux pour eux).

Je sais que cela ne poserait pas de problème si tout le monde utilisait ses propres counts avec sudo pour exécuter des commands privilégiées, mais en raison de circonstances hors de mon contrôle, ce n'est malheureusement pas une option.

Voici une façon stupide de le faire, qui ne fonctionne vraiment bien qu'avec l'authentification par key publique:

Tout d'abord, assurez-vous que votre machine locale a nc dessus.

Ensuite, créez un script (je l'appellerai connect-to-server ) sur votre machine locale et placez-le dans un endroit où votre ${PATH} sait *:

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

Ensuite, modifiez le .bashrc sur le système distant pour inclure quelque part:

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

Enfin, de return dans votre machine locale, éditez ~/.ssh/config pour append:

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

Les inconvénients de cette approche (et pourquoi je l'appelle stupide):

  • Si une command proxy est nécessaire, cela devient plus compliqué.
  • Si quelqu'un d'autre se connecte en même time, il se peut que le file .yourname pas encore été supprimé. Dans ce cas, ils obtiennent également l' set -o vi .
  • Surtout, si vous faites la ssh serverNickname command , la command s'exécutera, mais (puisque .bashrc n'est jamais source), le file .yourname rest, donc il serait poli d'avoir un second alias dans votre configuration ssh qui n'utilise pas le pseudo -proxy.

En fait, le seul avantage de cette approche est que votre command ssh n'a pas besoin d'argument supplémentaire.


* Si vous ne voulez pas changer quoi que ce soit sur les systèmes distants, voici un pseudo-proxy alternatif qui crée un temporaire .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 

Cela a tous les mêmes inconvénients de l'autre méthode, vous voudriez donc toujours un second alias dans votre configuration ssh qui n'invoque pas le pseudo-proxy.

J'irais pour:

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

mais si vous êtes un administrateur, vous pouvez essayer quelque chose de plus propre. Par exemple, vous pouvez utiliser l'option ssh SendEnv du côté client pour transmettre une variable spécifique, utiliser AcceptEnv dans la configuration sshd (côté server) pour l'accepter et, en fonction de cela, modifier le file .bashrc la racine pour ajuster le comportement en fonction de la valeur de la variable.

Cela implique de changer la configuration de sshd sur tous les hôtes ainsi que leur .bashrc . Pas exactement un "standalone" façon de faire, cependant …

Pour une solution facile côté client:

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

Cela échouera si les scripts d'initialisation du shell de la racine utilisent explicitement set -o emacs ou définit EDITOR sur emacs ou si le file .initrc la racine invoque les raccourcis keyboard emacs .

Le rest de cette réponse concerne les solutions côté server.


Cela fonctionne lorsque vous entrez dans la machine, puis utilisez sudo -i :

Pour votre /root/.bashrc :

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

Cela vous permet d'avoir un file bashrc personnel appelé /root/.bashrc-pasortingck où vous pouvez faire ce que vous voulez, comme set -o vi .

En combinant ceci avec une approche quelque peu naïve pour choisir ce file rc en fonction de $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="pasortingck" ;; 192.168.216.150*) person="lindsey" ;; esac fi if [[ -n "$person" ]] && [[ -f /root/.bashrc-"$person" ]]; then source /root/.bashrc-"$person" fi 

Cela ne fonctionne évidemment que si vous vous connectez à partir de la même adresse IP tout le time …

Une autre approche qui utilise le champ de commentaire de la key SSH particulière que vous utilisez, qui fonctionne si vous transférez l'agent SSH vers le server:

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

Ceci sélectionne le champ de commentaire de la key que vous avez utilisée pour vous connecter au server. La head -n 1 est là au cas où vous auriez plusieurs de vos keys dans le file authorized_keys .

Vous pouvez alors utiliser $ssh_comment pour choisir un file rc à la source, soit directement avec l'approche $SUDO_USER ci-dessus (dans laquelle le commentaire dans $ssh_comment peut-être subir un nettoyage s'il s'agit d'un path), soit via une déclaration de case comme l'approche $SSH_CLIENT .

Si vous voulez vraiment le faire sans modification côté server, soit:

1) Exécuter quelque chose comme

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

Je ne pense pas que la documentation soit trop claire à ce sujet, mais l' -o option est mentionnée et semble fonctionner.

2) Utilisez attendez:

Le script 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 

Rendez-le exécutable et exécutez:

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

Cela suppose que vous pouvez vous connecter sans entrer de passwords (pour l'hôte distant ou pour vos keys), sinon le script expect devrait en tenir count. Mais avec beaucoup de machines, vous avez probablement déjà cela. En outre, je m'attendais à un signe dollar et un espace, modifiez cela en fonction de votre message: "# " peut-être.

Bien que si quelque chose imprimé avant l'invite inclut ces mêmes caractères, vous devrez inclure quelque chose de plus spécifique dans la string attendue.

En outre, ce script ne supporte pas de donner des arguments supplémentaires à ssh . Si vous voulez exécuter une command explicite, vous n'avez probablement pas besoin de vi-mode, mais si vous avez besoin d'un tunnel de port, cela peut être un problème.


Mais en tout cas, je pense vraiment que cela devrait être résolu sur les systèmes cibles avec des counts séparés ( sudo ou tout simplement ancien UID 0). La configuration personnalisée serait également utile dans de nombreux autres cas et, en général, vous souhaiteriez définir un set de files de configuration et de variables d'environnement. (Considérez que les administrateurs pourraient ne pas être d'accord sur la valeur de $EDITOR , ou le contenu de virc ou autre chose.)

Supprimer également les users serait plus facile avec des counts distincts.

Tout moyen de synchroniser les files sur tous les hôtes résoudrait aussi sortingvialement cela en vous permettant de vous connecter avec quelque chose comme ssh -t user@host 'pasortingcks_shell.sh' ou ssh -t user@host 'bash --rcfile pasortingck.rc' .

vous pouvez avoir un file rc personnalisé:

http://docstore.mik.ua/orelly/networking_2ndEd/ssh/ch08_04.htm

ou injectez une action de command line dans votre file authorized_keys:

https://unix.stackexchange.com/a/214420/215465