如何在登录系统后自动将bash readline设置为vi模式?


9

我的团队负责数千台Linux / Unix计算机,因此,根帐户自然是在管理员之间“共享”的。我更喜欢vi模式,其他人更喜欢emacs模式。

如何在SSH登录到任何计算机时将bash的readline设置为vi模式,而又不强迫其他所有人也使用vi模式?

从本质上讲,它希望具有set -o vi登录后的效果,而不必每次都真正键入它,并且也不必强加给其他人(就像emacs模式对我来说很烦人,vi模式对他们来说很烦人)。

我知道,如果每个人都可以使用自己的sudo帐户执行特权命令,这将不是问题,但是由于我无法控制的情况,可悲的是这不是一个选择。


1
那不容易。一种方法是解析sshd的日志文件,并查看用于登录的密钥。我希望有一种客户端解决方案,例如,一种将本地readline配置传递到远程端或类似方式的方法,或者set -o vi在让我控制外壳程序之前,默默执行了一些黑暗的OpenSSH魔术。
Patrick

1
也许您可以在ssh进入服务器的客户端上使用Expect脚本,发送set -o vi命令,然后切换到交互模式。
Barmar

1
至少OpenSSH sshd设置了几个环境变量,这些变量可以帮助您确定另一端是谁。例如,SSH_CLIENT包含连接IP地址(以及客户端的传出/传入端口)。这个在摆弄~/.bashrc可能允许你做的事情只为你
萨米·莱恩

1
赏金表示您正在寻找“客户端解决方案”-那是什么?Unix主机上的ssh?油灰?蜂鸟?Java SSH?西格温?
杰夫·谢勒

1
您提到数以万计的机器。您是要从台机器开始并进入这些机器,还是要能够随身携带vi模式从一台机器跳到另一台机器?
icarus

Answers:


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 command,那么command它将运行,但是(因为.bashrc从不提供源)该.yourname文件仍然存在,因此在您的ssh配置中使用不使用伪代理的第二个别名是有礼貌的。

实际上,这种方法的唯一好处是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配置中的第二个别名,该别名不调用伪代理。


非常有创意。感谢您的建议。我已经广泛使用了ProxyCommand(某些网络/主机需要5跳以上才能到达),这将很快导致配置噩梦。编辑:查看所有答案,我认为您的答案最接近。
Patrick

4

我会去:

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

但如果您是管理员,则可以尝试一些更清洁的方法。例如,您可以SendEnv在客户端使用ssh 选项来传输特定变量,AcceptEnvsshd配置(服务器端)中使用它来接受它,然后在此基础上修改root的.bashrc文件,以根据变量的值来调整行为。

这意味着要更改sshd所有主机及其上的配置.bashrc。但是,这并不是完全“独立”的方式。


3

对于简单的客户端解决方案:

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

如果根的外壳初始化脚本显式使用set -o emacs或设置EDITORemacs,或者根的.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直接使用$SUDO_USER上面的方法(如果其中的注释$ssh_comment是路径名,则注释中的注释可能需要进行一些清理)或通过case与该$SSH_CLIENT方法相同的语句来选择一个rc文件作为源。


匹配SSH_CLIENTSUDO_USER是我当前使用的,但是它需要服务器端修改,并且不是特别可靠。我希望有一个纯粹的客户端解决方案。谢谢你的建议。
帕特里克

3

如果您确实想在服务器端进行修改而无需修改,请执行以下任一操作:

1)运行类似

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

我认为有关文档的内容并不太清楚,但是-o option已提及该文档,并且似乎可以正常工作。

2)使用期望:

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 ~$ 

假设您无需输入密码即可登录(对于远程主机或您的密钥),否则,期望脚本将需要考虑这一点。但是对于很多机器,您可能已经拥有了。另外,我希望有一个美元符号和一个空格,然后根据您的提示进行编辑:"# "也许。

尽管如果在提示前打印的内容包含相同的字符,则需要在预期的字符串中包含更具体的内容。

另外,该脚本不支持给额外的参数ssh。如果要给出一个明确的命令来运行,则可能不需要vi-mode,但是如果需要说端口隧道传输,那可能是个问题。


但是无论如何,我真的认为应该在具有单独帐户(sudo或只是普通的旧UID 0)的目标系统上解决此问题。个性化配置在其他许多情况下也很有用,通常,您需要设置很多配置文件和环境变量。(考虑到管理员可能不同意的价值$EDITOR,或其中的内容virc或其他内容。)

另外,使用单独的帐户删除用户会更容易。

通过在所有主机上同步文件的任何方式,也都可以通过允许您使用诸如ssh -t user@host 'patricks_shell.sh'或进行登录来轻松解决此问题ssh -t user@host 'bash --rcfile patrick.rc'


我考虑过使用Expect,但是正如您已经在问题中指出的那样,该问题与提示启动时所匹配的唯一项匹配interact。它不存在,提示可能与方式不同,配置文件中的motds /输出也是如此。(还是)感谢你的建议。
帕特里克

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.