Wie schließe ich Vim extern?

23

Angenommen, ich habe einen X11-Server, der hängt, sodass ich die Arbeit aus der XTerm Vim-Sitzung, die der X11-Server steuert, nicht speichern kann. (Nicht GVim, nur reguläres Vim-in-XTerm.)

Gibt es eine Möglichkeit, wie ich (von einem anderen Terminal aus) den laufenden Vim-Prozess anweisen kann, "alles zu speichern und zu beenden" von der Befehlszeile aus? Durch Senden eines Signals oder auf andere Weise?

Ich kenne Vim-Auslagerungsdateien und weiß, dass ich Vim einfach töten und mich vom Auslagerungsvorgang erholen kann. Ich frage, ob es einen "saubereren" Weg gibt.

DevSolar
quelle
6
Wenn diese Vim-Sitzungen mit einem aktivierten Server gestartet wurden (wie dies bei gvim standardmäßig der Fall ist), können Sie dazu die Client-Server-Funktionalität von Vim verwenden. Eine andere Möglichkeit könnte sein, mit reptyr die Vim-Programme auf ein neues Terminal zu zwingen, beispielsweise die TTYs, und sie dann zu schließen.
muru

Antworten:

25

Nachdem ich vor kurzem auf dieses Problem gestoßen war (über einen anderen Weg: Vim läuft auf einem Remote-Server und ich hatte den Bildschirm vergessen), entschied ich mich, nach einem Weg zu suchen.

Die erste Idee war, die von Vim verwendeten Dateideskriptoren nachzuschlagen und zu versuchen, darauf zu schreiben. Vims FDS zeigen auf das Psedoterminal, das vom Terminal-Emulator geöffnet wurde.

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

Meine ersten Versuche scheiterten jedoch:

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

Der ^[und ^Mwurden erhalten von CtrlVEscund CtrlVEnterverbunden.

Sie alle führten dazu, dass die Zeichen auf dem Terminal angezeigt wurden (ich habe dies lokal getestet, bevor ich es auf die Remote-Sitzung angewendet habe). Ich googelte herum und fand diesen SO-Beitrag , in dem Python zum Schreiben auf das Pseudoterminal-Gerät verwendet wurde:

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

Und das Ausprobieren auf einer interaktiven Python-Shell hat funktioniert:

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

Getan!

muru
quelle
1
Beachten Sie, dass das Python-Skript Root-Berechtigungen benötigt, um auf das Terminal zuzugreifen.
Martinkunev
6

Sie können Befehle extern an vim senden, wenn Sie ... ausführen.

Vim-Server

Zum Beispiel:

vim --servername vim

veranlasst vim, einen Server mit dem Namen "vim" zu starten. Wenn Sie es zweimal aufrufen, wird der neue Server "vim1", dreimal "vim2" usw. genannt. Möglicherweise möchten Sie einen Alias ​​für diesen Befehl erstellen.

Anhand des Fenstertitels können Sie erkennen, welchen Server eine bestimmte Instanz benannt hat. Wenn du siehst:

[Kein Name] + - VIM3

Der Servername ist "VIM3" ("vim3" bezieht sich auf dieselbe Instanz). Beachten Sie Folgendes, wenn Sie Folgendes sehen:

[Kein Name] + - VIM

Das bedeutet nicht unbedingt, dass es einen Server namens "VIM" hat. Sie können sicherstellen, dass der Server vorhanden ist, indem Sie die Servernamen wie folgt auflisten:

vim --serverlist

Dennoch stellt sich die Frage speziell nur für "VIM". Wenn Sie "GVIM" oder einen anderen Namen mit einer angehängten Nummer sehen, bedeutet dies, dass es sich um einen Server handelt.

Wie benutze ich den Client?

Nun können Sie auf Ihre Frage alle speichern und eine bestimmte vim-Instanz beenden, indem Sie Folgendes ausführen:

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

Wir verwenden die Escape-Taste, um in den normalen Modus zurückzukehren, falls Sie sich im Einfüge- oder Befehlsmodus befinden. Sie können auch etwas anderes tun :wqa, aber das scheint mir am besten geeignet zu sein, da die Auslagerungsdateien der Puffer, die nicht gespeichert werden konnten, erhalten bleiben (weil sie neu sind und keinen Dateinamen usw. haben).

Wenn Sie dies für alle Instanzen wie hier tun möchten, können Sie die Serverliste wie folgt durchlaufen:

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

Wenn es Ihnen aus irgendeinem Grund nicht gefällt --remote-send, können Sie stattdessen Folgendes verwenden, --remote-exprwas den Vorteil hat, dass der Client das Ergebnis oder den Fehler ausgibt, den er möglicherweise verursacht hat:

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

E141: No file name for buffer 1

Beachten Sie, dass für die Verwendung der Serverfunktionalität von Vim Vim mit dieser +clientserverOption erstellt wurde.

JoL
quelle
5

Installieren Sie den reptyrBefehl mit dem Paketmanager des Systems, z.

sudo apt install reptyr
pacman -Sy reptyr

Verwenden Sie dann den reptyrBefehl, um das ferne tty wie folgt auf das lokale (neue) tty umzustellen:

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

Wo PIDist die Prozess-ID aus der psBefehlsausgabe?

Bei dem Fehler:

Kann nicht an PID 12345 anhängen: Berechtigung verweigert

Ändern Sie den "ptrace scope" auf 0:

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

Sobald die vim-Sitzung von der alten auf die neue Sitzung umgestellt wurde, speichern und beenden Sie sie wie gewohnt. Beachten Sie, dass Sie möglicherweise drücken müssen Enter, um die Konsole zu aktualisieren.

Dave Jarvis
quelle
0

Was ist, wenn du Vim anmutig tötest?

kill -s 15 -p [PID for Vim]

kill -s (signal) 15 heißt SIGTERM und teilt diesem Prozess mit, dass er sich ordnungsgemäß herunterfahren soll.

Um die PID (Process ID) von Vim zu erhalten, verwenden Sie:
ps ax | grep vim

Gustav Blomqvist
quelle
1
Vim schreibt nicht automatisch nicht gespeicherte Änderungen, egal welche Signale gesendet wurden.
muru