Vim'i harici olarak nasıl kapatırım?


23

Diyelim ki asılı olan bir X11 sunucum var, bu da beni X11 sunucusunun kontrol ettiği XTerm Vim oturumundan kurtarmamı engelliyor. (GVim değil, sadece normal Vim-in-XTerm.)

(Farklı bir terminalden) çalışan Vim işlemine komut satırından "hepsini kaydet & çık" diyebilmemin bir yolu var mı? Bir sinyal göndererek veya başka bir yöntemle mi?

Vim takas dosyalarını biliyorum ve Vim'i öldürüp takastan kurtulabileceğimi biliyorum. "Temizleyici" bir yol olup olmadığını soruyorum.


6
Bu Vim oturumları etkin bir sunucu ile başlatılmışsa (varsayılan olarak gvim'in yaptığı gibi), bunu yapmak için Vim'in istemci-sunucu işlevini kullanabilirsiniz. Diğer bir seçenek de Vim programlarını yeni bir terminale zorlamak, TTY’leri söylemek ve bunları kapatmak için reptyr kullanmak olabilir.
muru

Yanıtlar:


25

Yakın zamanda bu soruna rastladım (başka bir yolla: Vim uzak bir sunucuda çalışıyor ve ekranı unuttum), bir yol aramaya karar verdim.

İlk fikir, Vim tarafından kullanılan dosya tanımlayıcılarına bakmak ve yazmaya çalışmaktı. Vim'in fds'i, terminal emülatör tarafından açılan psedoterminali işaret ediyor, doğal olarak:

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

Ancak ilk birkaç denemem başarısız oldu:

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

^[Ve ^Melde edilmiştir CtrlVEscve CtrlVEntersırasıyla.

Hepsi terminalde gösterilen karakterlerle sonuçlandı (uzak oturuma uygulamadan önce bunu yerel olarak test ediyordum). Etrafta dolaşırken, bu SO postasını pseudoterminal cihaza yazmak için Python kullanarak buldum :

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

Ve etkileşimli bir python kabuğu üzerinde denemek çalıştı:

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

Bitti!


1
Python betiğinin terminale erişmek için kök izinleri gerektirdiğini unutmayın.
martinkunev

6

Koşturuyorsanız, harici olarak vim'e komut gönderebilirsiniz ...

Vim sunucuları

Örneğin, yapıyoruz:

vim --servername vim

vim'in "vim" adında bir sunucu başlatmasına neden olur. İki kez arayın ve yeni sunucu "vim1" olarak adlandırılır, üç kez ve "vim2" vb. Olarak adlandırılır.

Pencere başlığına bakarak belirli bir örneğin hangi sunucunun adlandırıldığını görebilirsiniz. Gördüğünde:

[İsim Yok] + - VIM3

sunucu adı büyük / küçük harf duyarsızdır "VIM3" ("vim3" aynı örneğe atıfta bulunacaktır). Eğer görürseniz şunu unutmayın:

[İsim Yok] + - VIM

Bu mutlaka "VIM" adında bir sunucuya sahip olduğu anlamına gelmez. Sunucu adlarını aşağıdakilerle listeleyerek sunucunun var olduğundan emin olabilirsiniz:

vim --serverlist

Yine de, soru özellikle "VIM" için ortaya çıkar. "GVIM" veya eklenmiş bir numaraya sahip başka bir isim görürseniz, bunun bir sunucu olduğu anlamına gelir.

İstemci nasıl kullanılır?

Şimdi, sorunuz üzerine, hepsini kaydedebilir ve belirli bir vim örneğinden çıkabilirsiniz, örneğin:

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

Ekleme veya komut modunda olma ihtimaline karşı normal moda dönmek için kaçış özelliğini kullanıyoruz. Başka bir şey yapabilirsin :wqa, ama bu benim için en uygun olanı çünkü kurtarılamayan tamponların takas alanlarını bırakacakları (çünkü yeni ve bir dosya adına sahip değiller).

Buradaki durumunuzdaki tüm örnekler için bunu yapmak istiyorsanız, aşağıdaki gibi sunucu listesinde dolaşabilirsiniz:

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

Bazı nedenlerden hoşlanmıyorsanız --remote-send, bunun yerine --remote-expr, istemcinin sonucu ya da neden olabileceği hatayı vermesine neden olma avantajı olan kullanımı kullanabilirsiniz :

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

E141: No file name for buffer 1

Vim'in sunucu işlevselliğini kullanmanın Vim'in seçenekle oluşturulduğunu gerektirdiğini unutmayın +clientserver.


5

reptyrKomutu, sistemin paket yöneticisini kullanarak kurun :

sudo apt install reptyr
pacman -Sy reptyr

Ardından reptyruzak tty'yi yerel (yeni) tty'ye aşağıdaki gibi değiştirmek için komutu kullanın:

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

Komut çıkışındaki PIDişlem kimliği nerede ps.

Hata üzerine:

Pideye eklenemiyor 12345: İzin reddedildi

"Ptrace kapsamını" 0 olarak değiştirin:

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

Vim oturumu eski oturumdan yenisine geçtiğinde, her zamanki gibi kaydedin ve çıkın. EnterKonsolu yenilemek için basmanız gerekebileceğini unutmayın .


0

Ya zarifçe Vim'i öldürürsen?

kill -s 15 -p [PID for Vim]

kill -s (sinyal) 15, SIGTERM olarak adlandırılır ve bu sürecin kendisini zarif bir şekilde kapatmasını söyler.

Vim kullanımının PID'sini (İşlem Kimliği) almak için:
ps ax | grep vim


1
Vim, hangi sinyallerin gönderildiğine bakılmaksızın kaydedilmemiş değişiklikleri otomatik olarak yazmaz.
muru,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.