How to set bash readline to vi mode automatically upon login to a system?
I'd go for:
ssh server -t "bash --login -o vi"
but it you are an admin, you can try something cleaner. For example you could use the ssh SendEnv
option on the client side to transmit a specific variable, use AcceptEnv
in the sshd
configuration (server side) to accept it, and based on this, modify root's .bashrc
file to adjust behaviour according to the value of the variable.
This implies to change the sshd
configuration on all hosts as well as their .bashrc
. Not exactly a "standalone" way to do, however...
For an easy client side solution:
alias connect='ssh -t root@server "bash -o vi"'
This will fail if the root's shell initialization scripts explicitly uses set -o emacs
or sets EDITOR
to emacs
, or if root's .initrc
file invokes emacs
key bindings.
The rest of this answer concerns server-side solutions.
This works when you are ssh
-ing into the machine and then use sudo -i
:
For your /root/.bashrc
:
if [[ -n "$SUDO_USER" ]] && [[ -f /root/.bashrc-"$SUDO_USER" ]]; then
source /root/.bashrc-"$SUDO_USER"
fi
This allows you to have a personal bashrc
file called /root/.bashrc-patrick
wherein you can do whatever you like, like set -o vi
.
Combining this with a somewhat naive approach to picking that rc file up depending on $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
This obviously only works if you're connecting from the same IP address all the time...
Another approach which uses the comment field of the particular SSH key you're using, which works if you're forwarding the SSH agent to the server:
ssh_comment="$( ssh-add -L | grep -f /root/.ssh/authorized_keys | awk '{ print $NF '} | head -n 1 )"
This picks out the comment field for the key that you used to connect to the server. The head -n 1
is there in case you happen to have several of your keys in the authorized_keys
file.
You may then use $ssh_comment
to pick an rc file to source, either directly as with the $SUDO_USER
approach above (in which the comment in $ssh_comment
may need to undergo some cleanup if it's a pathname), or via a case
statement as with the $SSH_CLIENT
approach.
If you really want to do it without modification on the server side, either:
1) Run something like
$ ssh user@host -t 'bash -l -o vi'
I don't think the documentation is too clear on that, but -o option
is mentioned, and seems to work.
2) Use expect:
The expect
script:
$ 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
Make it executable and run:
$ ./bashsetup.expect user testhost
spawn ssh -l user testhost
[motd, blahblah...]
user@testhost ~$ set -o vi
user@testhost ~$
This assumes you can login without entering passwords (for the remote host or for your keys), otherwise the expect script would need to take that into account. But with lots of machines you're likely to already have that. Also, I expected for a dollar sign and a space, edit that according to your prompt: "# "
perhaps.
Though if something printed before prompt includes those same characters, you'll need to include something more specific in the expected string.
Also, that script doesn't support giving extra arguments to ssh
. If you're going to give an explicit command to run, you probably don't need vi-mode, but if you need say port tunneling, that might be a problem.
But in any case, I really think this should be solved on the target systems with separate accounts (sudo
or just plain old UID 0). Personalised configuration would be useful for many other cases too, and in general you'd have a bunch of configuration files and environment variables you'd like to set. (Consider that the admins might not agree on the value of $EDITOR
, or the contents of virc
or whatever.)
Also removing users would be easier with separate accounts.
Any way of synchronising files on all the hosts would also trivially solve this by allowing you to login with something like ssh -t user@host 'patricks_shell.sh'
or ssh -t user@host 'bash --rcfile patrick.rc'
.