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'.