在MS-Windows上玩Emacs可谓「筚路蓝缕」,借助Emacs 26.x的新特性“Connection Local Variables”,总算能让MS-Windows到*NIX系统的shell连接优雅一些。

背景

我以前的解决方案是写一个函数,这已经让登录远程系统容易很多了。以前的文章已经介绍了两个简化的方法:

  • ~/.ssh/config里添加服务器信息,可以用名字来选择服务器。
  • 定义函数快速登录服务器,M-x bandwagon-shell RET就可以登录到服务器啦。

还有一个上面没有写,SSH keys,看这篇Arch Linux的wiki讲的比我清楚多了。

之前文章没说的是一个Bug,因为本地Windows系统shell设置是Windows程序,而远程*NIX系统的shell需要是bash一类的,所以如果用上面文章里的代码而在Windows没有配置使用bash作为shell的话会出错。一个绕过的方法是

1
2
3
4
5
(defun bandwagon-shell ()
(interactive)
(let ((default-directory "/scpx:bandwagon:/root/")
(explicit-shell-file-name "/bin/bash"))
(shell (generate-new-buffer-name "*Bandwagon*"))))

但这样又带来一些奇奇怪怪的问题。而且,如果你有很多的服务器,每个都这么写,多麻烦。以上的方法我用了一两年,始终觉得不好,再加上服务器越来越多,越来越觉得力不从心。必须要做点改变了。

用宏批量定义函数

受emacs-china里LdBeth回答的启发,写了如下的宏

1
2
3
4
5
(defmacro make--shell (name &rest arglist)
`(defun ,(intern (format "%S-shell" name)) ,arglist
(interactive)
(let ((default-directory ,(format "/scpx:%S:" name)))
(shell (generate-new-buffer-name ,(format "*%S*" name))))))

这样直接用宏来生成函数

1
(make--shell bandwagon)

用连接局部变量定义远程shell

先上代码,以登录到SDF为例

1
2
3
4
5
6
7
8
(connection-local-set-profile-variables
'remote-bash-sdf
'((explicit-shell-file-name . "/usr/pkg/bin/bash")
(explicit-bash-args . ("-himBH"))))

(connection-local-set-profiles
`(:application tramp :protocol "scpx" :machine "sdf")
'remote-bash-sdf)

首先定义了一个用于SDF服务器的配置,有shell和相应的参数,然后把是这个配置应用于相应的连接,非常优雅。其实还可以更优雅啊,比如下面的代码把我所有的服务器和两种对应的服务都一块定义了

1
2
3
4
5
(dolist (m '("bandwagon" "E5" "pandorabox"))
(dolist (p '("sshx" "scpx"))
(connection-local-set-profiles
`(:application tramp :protocol ,p :machine ,m)
'remote-bash)))

感觉怎么样?