Làm thế nào để tôi đóng Vim bên ngoài?


23

Giả sử tôi có một máy chủ X11 đang bị treo, ngăn tôi lưu công việc từ phiên Xt Verm mà máy chủ X11 điều khiển. (Không phải GVim, chỉ là Vim-in-XTerm thông thường.)

Có cách nào tôi có thể (từ một thiết bị đầu cuối khác) nói với quy trình Vim đang chạy để "lưu tất cả & thoát" khỏi dòng lệnh không? Bằng cách gửi tín hiệu, hoặc thông qua một số phương tiện khác?

Tôi biết về các tập tin hoán đổi Vim, và rằng tôi có thể giết Vim và phục hồi từ trao đổi. Tôi đang hỏi nếu có một cách "sạch" hơn.


6
Nếu các phiên Vim đó được bắt đầu với một máy chủ được bật (như gvim theo mặc định), thì bạn có thể sử dụng chức năng máy khách-máy chủ của Vim để làm như vậy. Một tùy chọn khác có thể là sử dụng reptyr để buộc các chương trình Vim đến một thiết bị đầu cuối mới, giả sử các TTY và đóng chúng sau đó.
muru

Câu trả lời:


25

Gần đây đã gặp phải vấn đề này (thông qua một cách khác: Vim chạy trên một máy chủ từ xa và tôi đã quên màn hình), tôi quyết định tìm kiếm một cách.

Ý tưởng đầu tiên là tìm kiếm các mô tả tập tin được sử dụng bởi Vim và thử viết nó. Các fds của Vim trỏ đến psedoterminal được mở bởi trình giả lập thiết bị đầu cuối, đủ tự nhiên:

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

Tuy nhiên, một vài lần thử đầu tiên của tôi đã thất bại:

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

Các ^[^Mđược thu được bởi CtrlVEscCtrlVEnter, tương ứng.

Tất cả đều dẫn đến các ký tự hiển thị trên thiết bị đầu cuối (Tôi đã thử nghiệm điều này cục bộ, trước khi áp dụng nó cho phiên từ xa). Googling xung quanh, tôi tìm thấy bài viết SO này , sử dụng Python để ghi vào thiết bị giả hành:

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

Và thử nó trên một vỏ python tương tác đã làm việc:

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

Làm xong!


1
Lưu ý rằng tập lệnh python yêu cầu quyền root để truy cập vào thiết bị đầu cuối.
martinkunev

6

Bạn có thể gửi lệnh đến vim bên ngoài nếu bạn đang chạy ...

Máy chủ Vim

Ví dụ: làm:

vim --servername vim

sẽ khiến vim khởi chạy một máy chủ có tên "vim". Gọi nó hai lần và máy chủ mới sẽ được gọi là "vim1", gọi nó là ba lần và nó sẽ là "vim2", v.v. Bạn có thể muốn tạo bí danh cho lệnh đó.

Bạn có thể biết máy chủ cụ thể nào được đặt tên bằng cách nhìn vào tiêu đề cửa sổ. Khi bạn thấy:

[Không tên] + - VIM3

tên máy chủ không phân biệt chữ hoa chữ thường "VIM3" ("vim3" sẽ đề cập đến cùng một ví dụ.). Lưu ý rằng nếu bạn thấy:

[Không tên] + - VIM

điều đó không nhất thiết có nghĩa là nó có một máy chủ tên là "VIM". Bạn có thể đảm bảo máy chủ tồn tại bằng cách liệt kê tên máy chủ với:

vim --serverlist

Tuy nhiên, câu hỏi chỉ đặt ra cho "VIM", cụ thể. Nếu bạn thấy "GVIM" hoặc một số tên khác có số được gắn vào nó, thì đó có nghĩa là máy chủ.

Cách sử dụng máy khách

Bây giờ, vào câu hỏi của bạn, bạn có thể lưu tất cả và thoát khỏi một ví dụ vim đã cho bằng cách thực hiện, ví dụ:

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

Chúng tôi sử dụng lối thoát để trở về chế độ bình thường trong trường hợp bạn đang ở chế độ chèn hoặc lệnh. Bạn có thể làm một cái gì đó khác :wqa, nhưng điều đó có vẻ phù hợp nhất với tôi vì nó sẽ để lại các bộ đệm không thể lưu (vì chúng mới và không có tên tệp, v.v.).

Nếu bạn muốn làm như vậy cho tất cả các trường hợp như trong trường hợp của bạn ở đây, bạn có thể chỉ cần lặp qua danh sách máy chủ như vậy:

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

Nếu vì lý do nào đó bạn không thích --remote-send, thay vào đó bạn có thể sử dụng --remote-exprlợi thế là nó sẽ khiến máy khách đưa ra kết quả hoặc lỗi mà nó có thể gây ra, như vậy:

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

E141: No file name for buffer 1

Lưu ý rằng việc sử dụng chức năng máy chủ của Vim yêu cầu Vim được xây dựng với +clientservertùy chọn.


5

Cài đặt reptyrlệnh bằng trình quản lý gói của hệ thống, chẳng hạn như:

sudo apt install reptyr
pacman -Sy reptyr

Sau đó sử dụng reptyrlệnh để chuyển tty từ xa sang tty cục bộ (mới), như sau:

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

Trong trường hợp PIDlà quá trình ID từ psđầu ra lệnh.

Khi có lỗi:

Không thể đính kèm với pid 12345: Quyền bị từ chối

Thay đổi "phạm vi ptrace" thành 0:

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

Khi phiên vim đã được hoán đổi từ phiên cũ sang phiên mới, hãy lưu và thoát như bình thường. Lưu ý rằng bạn có thể phải nhấn Enterđể làm mới giao diện điều khiển.


0

Nếu bạn duyên dáng giết Vim thì sao?

kill -s 15 -p [PID for Vim]

kill -s (signal) 15 được gọi là SIGTERM wich nói rằng quá trình đó tự tắt một cách duyên dáng.

Để có được PID (ID tiến trình) của Vim, hãy sử dụng:
ps ax | grep vim


1
Vim không tự động viết các thay đổi chưa lưu, bất kể tín hiệu nào được gửi.
muru
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.