¿Cómo cierro Vim externamente?


23

Digamos que tengo un servidor X11 que está colgando, evitando que guarde el trabajo de la sesión XTerm Vim que controla el servidor X11. (No GVim, solo Vim-in-XTerm normal).

¿Hay alguna manera de que pueda (desde una terminal diferente) decirle al proceso Vim en ejecución que "guarde todo y salga" de la línea de comando? ¿Enviando una señal o por algún otro medio?

Sé acerca de los archivos de intercambio de Vim, y que podría matar a Vim y recuperarme del intercambio. Estoy preguntando si hay una forma "más limpia".


66
Si esas sesiones de Vim se iniciaron con un servidor habilitado (como lo hace gvim de forma predeterminada), entonces podría usar la funcionalidad cliente-servidor de Vim para hacerlo. Otra opción podría ser usar reptyr para forzar los programas Vim a un nuevo terminal, digamos los TTY, y luego cerrarlos.
muru

Respuestas:


25

Recientemente me he encontrado con este problema (de otra manera: Vim ejecutándose en un servidor remoto, y había olvidado la pantalla), decidí buscar una forma.

La primera idea fue buscar los descriptores de archivo utilizados por Vim e intentar escribir en él. Los fds de Vim apuntan al terminal psedoterminal abierto por el emulador de terminal, naturalmente:

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

Sin embargo, mis primeros intentos fallidos:

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

Los ^[y ^Mfueron obtenidos por CtrlVEscy CtrlVEnter, respectivamente.

Todos dieron como resultado que los caracteres aparecieran en el terminal (estaba probando esto localmente, antes de aplicarlo a la sesión remota). Buscando en Google, encontré esta publicación SO , usando Python para escribir en el dispositivo pseudoterminal:

#!/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)

Y probarlo en un shell interactivo de Python funcionó:

$ sudo python3
Python 3.5.0 (default, Sep 20 2015, 11:28:25) 
[GCC 5.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os, fcntl, termios
>>> fd = os.open('/dev/pts/14', os.O_RDWR)
>>> a = '\033:wqa!\n'
>>> for i in a: fcntl.ioctl(fd, termios.TIOCSTI, i);
... 
b'\x1b'
b':'
b'w'
b'q'
b'a'
b'!'
b'\n'
>>> 

¡Hecho!


1
Tenga en cuenta que el script python requiere permisos de root para acceder al terminal.
martinkunev

6

Puede enviar comandos a vim externamente si está ejecutando ...

Servidores Vim

Por ejemplo, haciendo:

vim --servername vim

hará que vim inicie un servidor con el nombre "vim". Llámelo dos veces y el nuevo servidor se llamará "vim1", llámelo tres veces y será "vim2", etc. Es posible que desee crear un alias de ese comando.

Puede saber qué servidor se nombra una instancia en particular mirando el título de la ventana. Cuando veas:

[Sin nombre] + - VIM3

el nombre del servidor distingue entre mayúsculas y minúsculas "VIM3" ("vim3" se referiría a la misma instancia). Tenga en cuenta que si ve:

[Sin nombre] + - VIM

eso no significa necesariamente que tenga un servidor llamado "VIM". Puede asegurarse de que el servidor existe enumerando los nombres del servidor con:

vim --serverlist

Aún así, la pregunta solo surge para "VIM", específicamente. Si ve "GVIM" o algún otro nombre con un número adjunto, significa que es un servidor.

Cómo usar el cliente

Ahora, en su pregunta, puede guardar todo y salir de una instancia vim dada haciendo, por ejemplo:

vim --servername vim2 --remote-send $'\e:wqa\n'

Usamos el escape para volver al modo normal en caso de que esté en modo de inserción o comando. Puede hacer otra cosa que no sea :wqa, pero eso me parece más apropiado porque dejará los archivos de intercambio de buffers que no se pudieron guardar (porque son nuevos y no tienen un nombre de archivo, etc.).

Si desea hacerlo para todas las instancias, como en su caso aquí, puede recorrer la lista de servidores de esta manera:

for instance in $(vim --serverlist); do
  vim --servername $instance --remote-send $'\e:wqa\n'
done

Si por alguna razón no le gusta --remote-send, puede usar el --remote-exprque tiene la ventaja de que causará que el cliente muestre el resultado o el error que podría haber causado, así:

$ vim --servername vim2 --remote-expr 'execute("wqa")'

E141: No file name for buffer 1

Tenga en cuenta que el uso de la funcionalidad del servidor de Vim requiere que Vim se haya creado con la +clientserveropción.


5

Instale el reptyrcomando utilizando el administrador de paquetes del sistema, como:

sudo apt install reptyr
pacman -Sy reptyr

Luego use el reptyrcomando para cambiar el tty remoto al tty local (nuevo), de la siguiente manera:

ssh user@remote-hostname
ps auxw | grep -i vim
reptyr PID

¿Dónde PIDestá la ID del proceso de la pssalida del comando?

Ante el error:

No se puede adjuntar a pid 12345: permiso denegado

Cambie el "alcance de ptrace" a 0:

sudo su -
echo 0 > /proc/sys/kernel/yama/ptrace_scope

Una vez que la sesión vim se ha cambiado de la sesión anterior a la nueva, guarde y salga como de costumbre. Tenga en cuenta que puede que tenga que presionar Enterpara actualizar la consola.


0

¿Qué pasa si matas con gracia a Vim?

kill -s 15 -p [PID for Vim]

kill -s (señal) 15 se llama SIGTERM, que le dice a ese proceso que se cierre con gracia.

Para obtener el PID (ID de proceso) de Vim use:
ps ax | grep vim


1
Vim no escribe automáticamente los cambios no guardados, sin importar qué señales se enviaron.
muru
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.