Come posso chiudere Vim esternamente?


23

Diciamo che ho un server X11 sospeso, che mi impedisce di salvare il lavoro dalla sessione XTerm Vim controllata dal server X11. (Non GVim, solo Vim-in-XTerm normale.)

C'è un modo in cui potrei (da un altro terminale) dire al processo Vim in esecuzione di "salvare tutto ed uscire" dalla riga di comando? Inviando un segnale o attraverso altri mezzi?

Conosco i file di scambio di Vim e potrei semplicemente uccidere Vim e recuperare dallo scambio. Sto chiedendo se esiste un modo "più pulito".


6
Se quelle sessioni Vim sono state avviate con un server abilitato (come gvim fa per impostazione predefinita), è possibile utilizzare la funzionalità client-server di Vim per farlo. Un'altra opzione potrebbe essere quella di utilizzare reptyr per forzare i programmi Vim su un nuovo terminale, dire i TTY e chiuderli.
muru,

Risposte:


25

Avendo recentemente riscontrato questo problema (in un altro modo: Vim in esecuzione su un server remoto e avevo dimenticato lo schermo), ho deciso di cercare un modo.

La prima idea era quella di cercare i descrittori di file utilizzati da Vim e provare a scriverlo. Le fds di Vim indicano il psedoterminale aperto dall'emulatore terminale, abbastanza 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]

Tuttavia, i miei primi tentativi falliti:

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

Gli ^[e ^Msono stati ottenuti da CtrlVEsce CtrlVEnter, rispettivamente.

Tutti hanno portato alla comparsa dei personaggi sul terminale (lo stavo testando localmente, prima di applicarlo alla sessione remota). Cercando su Google, ho trovato questo post SO , usando Python per scrivere sul dispositivo pseudoterminale:

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

E provarlo su una shell interattiva in pitone ha funzionato:

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

Fatto!


1
Si noti che lo script python richiede le autorizzazioni di root per accedere al terminale.
martinkunev,

6

Puoi inviare comandi a vim esternamente se stai eseguendo ...

Server Vim

Ad esempio, facendo:

vim --servername vim

farà sì che vim avvii un server con il nome "vim". Chiamalo due volte e il nuovo server si chiamerà "vim1", chiamalo tre volte e sarà "vim2", ecc. Potresti voler creare un alias di quel comando.

Puoi sapere a quale server viene assegnata una determinata istanza guardando il titolo della finestra. Quando vedi:

[Nessun nome] + - VIM3

il nome del server non fa distinzione tra maiuscole e minuscole "VIM3" ("vim3" si riferirà alla stessa istanza). Nota che se vedi:

[Nessun nome] + - VIM

ciò non significa necessariamente che abbia un server chiamato "VIM". Puoi assicurarti che il server esista elencando i nomi dei server con:

vim --serverlist

Tuttavia, la domanda sorge solo per "VIM", in particolare. Se vedi "GVIM" o qualche altro nome con un numero ad esso aggiunto, significa che è un server.

Come usare il client

Ora, sulla tua domanda, puoi salvare tutto ed uscire da una determinata istanza di vim facendo, ad esempio:

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

Usiamo l'escape per tornare alla modalità normale nel caso tu sia in modalità inserimento o comando. Puoi fare qualcosa di diverso :wqa, ma questo mi sembra più appropriato perché lascerà i file di scambio di buffer che non possono essere salvati (perché sono nuovi e non hanno un nome file, ecc.).

Se vuoi farlo per tutte le istanze come nel tuo caso qui, puoi semplicemente scorrere l'elenco dei server in questo modo:

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

Se per qualche motivo non ti piace --remote-send, puoi invece utilizzare --remote-exprquale ha il vantaggio di far sì che il client produca il risultato o l'errore che potrebbe aver causato, in questo modo:

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

E141: No file name for buffer 1

Si noti che l'utilizzo della funzionalità del server di Vim richiede che Vim sia stato creato con l' +clientserveropzione.


5

Installa il reptyrcomando usando il gestore pacchetti del sistema, come ad esempio:

sudo apt install reptyr
pacman -Sy reptyr

Quindi utilizzare il reptyrcomando per passare da remoto tty a locale (nuovo) tty, come segue:

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

Dove si PIDtrova l'ID processo psdall'output del comando.

All'errore:

Impossibile collegarsi al pid 12345: autorizzazione negata

Modificare "ambito ptrace" su 0:

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

Una volta che la sessione vim è stata scambiata dalla sessione precedente a quella nuova, salvare ed uscire come al solito. Si noti che potrebbe essere necessario premere Enterper aggiornare la console.


0

E se uccidi con grazia Vim?

kill -s 15 -p [PID for Vim]

kill -s (segnale) 15 è chiamato SIGTERM che dice a quel processo di chiudersi con grazia.

Per ottenere il PID (Process ID) di Vim usare:
ps ax | grep vim


1
Vim non scrive automaticamente le modifiche non salvate, indipendentemente dai segnali inviati.
Muru,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.