是否可以(从另一个终端)告诉正在运行的Vim进程从命令行“保存并退出” ?通过发送信号或通过其他方式?
我了解Vim交换文件,因此我可以杀死Vim并从交换中恢复。我问是否有一种“清洁”的方式。
#1 楼
最近遇到了这个问题(通过另一种方式:Vim在远程服务器上运行,但我忘记了屏幕),我决定寻找一种方法。第一个想法是查找Vim使用的文件描述符,并尝试对其进行写入。 Vim的fds自然指向由终端仿真器打开的psedoterminal:
$ ls -l /proc/$(pgrep -n vim)/fd/
total 0
lrwx------ 1 muru muru 64 Nov 17 01:25 0 -> /dev/pts/14
lrwx------ 1 muru muru 64 Nov 17 01:25 1 -> /dev/pts/14
lrwx------ 1 muru muru 64 Nov 17 01:25 2 -> /dev/pts/14
lrwx------ 1 muru muru 64 Nov 17 01:25 3 -> socket:[99564312]
,我最初的几次尝试失败了:
echo '^[:wq^M' > /proc/$(pgrep -n vim)/fd/0
echo ':wq^M' > /proc/$(pgrep -n vim)/fd/0
echo ':wq^M' > /proc/$(pgrep -n vim)/fd/0
echo '^C' > /proc/$(pgrep -n vim)/fd/0
printf "%s" '^[:wqa!^M' > /proc/$(pgrep -n vim)/fd/0
^[
和^M
是通过CtrlVEsc和分别按CtrlVEnter。它们都导致字符显示在终端上(在将其应用于远程会话之前,我正在本地进行测试)。在Google上四处搜寻,我发现了这篇SO帖子,使用Python编写了伪终端设备:
/>并在交互式python shell上进行尝试:
#!/usr/bin/python
import sys,os,fcntl,termios
if len(sys.argv) != 3:
sys.stderr.write("usage: ttyexec.py tty command\n")
sys.exit(1)
fd = os.open("/dev/" + sys.argv[1], os.O_RDWR)
cmd=sys.argv[2]
for i in range(len(cmd)):
fcntl.ioctl(fd, termios.TIOCSTI, cmd[i])
fcntl.ioctl(fd, termios.TIOCSTI, '\n')
os.close(fd)
完成! br />
评论
请注意,python脚本需要root权限才能访问终端。
–martinkunev
18年8月16日在22:44
#2 楼
如果您正在运行,则可以从外部向vim发送命令...Vim服务器
例如,执行以下操作:
vim --servername vim
将使vim启动名称为“ vim”的服务器。调用两次,新服务器将被命名为“ vim1”,三次将被命名为“ vim2”,依此类推。您可能想对该命令进行别名。服务器通过查看窗口标题来命名特定实例。当您看到:
[无名称] +-VIM3
服务器名称不区分大小写“ VIM3”(“ vim3”指同一实例。)。请注意,如果您看到:
[无名称] +-VIM
,这不一定意味着它有一个名为“ VIM”。您可以通过列出服务器名称来确保服务器存在:
vim --serverlist
不过,问题仅在“ VIM”出现。如果您看到“ GVIM”或其他名称后加数字,则表示它是服务器。
如何使用客户端
现在,您的问题,您可以保存所有内容并通过执行以下操作退出给定的vim实例,例如:命令模式。您可以执行
:wqa
以外的其他操作,但是这对我来说似乎最合适,因为它将留下无法保存的缓冲区交换文件(因为它们是新文件并且没有文件名等)。如果要针对所有实例(例如此处的情况)这样做,则可以像这样遍历服务器列表:
vim --servername vim2 --remote-send $'\e:wqa\n'
由于某些原因,您不喜欢
--remote-send
,可以改用--remote-expr
,其优点是将导致客户端输出结果或可能导致的错误,例如: br /> 请注意,使用Vim的服务器功能要求Vim是使用
+clientserver
选项构建的。#3 楼
使用系统的软件包管理器安装reptyr
命令,例如:sudo apt install reptyr
pacman -Sy reptyr
然后使用
reptyr
命令将远程tty切换到本地(新)tty,如下所示:ssh user@remote-hostname
ps auxw | grep -i vim
reptyr PID
其中
PID
是来自ps
命令输出的进程ID。出现错误:
无法附加到pid 12345:权限被拒绝
将“ ptrace范围”更改为0:
sudo su -
echo 0 > /proc/sys/kernel/yama/ptrace_scope
vim会话从旧会话切换到新会话后,照常保存并退出。请注意,您可能必须按Enter刷新控制台。
评论
reptyr绝对是进行此类工作的最佳工具...就像Linux的柱塞一样:D
– Avio
20-2-20在14:27
#4 楼
如果您优雅地杀死Vim怎么办?kill -s 15 -p [PID for Vim]
kill -s(信号)15被称为SIGTERM,它告诉该进程正常关闭自身。 Vim使用的进程ID):
ps ax | grep vim
评论
无论发送哪个信号,Vim都不会自动写入未保存的更改。
–muru
17年9月15日在5:22
#5 楼
我不知道它是否能正常工作,但是您可以尝试安装一个自动听SigUSR1
的命令:augroup save_and_exit | au!
au SigUSR1 * wall | qa!
augroup END
然后,从另一个外壳中,您可以运行:
$ kill -s USR1 1234
其中
1234
是Vim进程的pid。在Vim中,可以通过getpid()
函数获得后者。这需要补丁8.2.0952来获取
SigUSR1
事件。
评论
如果这些Vim会话是在启用服务器的情况下启动的(例如gvim会默认启用),则可以使用Vim的客户端-服务器功能来实现。另一种选择可能是使用reptyr将Vim程序强制到一个新的终端(例如TTY),然后关闭它们。