Vim을 외부에서 어떻게 닫습니까?


23

X11 서버가 멈추고 X11 서버가 제어하는 ​​XTerm Vim 세션에서 작업을 저장하지 못하게한다고 가정 해 봅시다. (GVim이 아니라 정규 Vim-in-XTerm)

다른 터미널에서 실행중인 Vim 프로세스에 명령 줄에서 "모두 저장 및 종료"하도록 지시 할 수있는 방법이 있습니까? 신호를 보내거나 다른 수단을 통해?

Vim 스왑 파일에 대해 알고 있으며 Vim을 죽이고 스왑에서 복구 할 수 있습니다. "깨끗한"방법이 있는지 묻습니다.


6
Vim 세션이 서버가 활성화 된 상태에서 시작된 경우 (gvim은 기본적으로 수행함) Vim의 클라이언트-서버 기능을 사용하여이를 수행 할 수 있습니다. 또 다른 옵션은 reptyr을 사용하여 Vim 프로그램을 새 터미널로 강제로 보내고 TTY라고 말한 다음 닫는 것입니다.
muru

답변:


25

최근에 다른 방법으로 원격 서버에서 Vim을 실행하고 화면을 잊어 버렸습니다.이 문제에 부딪 치면서 길을 찾기로 결정했습니다.

첫 번째 아이디어는 Vim이 사용하는 파일 디스크립터를 찾아서 작성하는 것입니다. Vim의 fd는 터미널 에뮬레이터에 의해 열린 psedoterminal을 자연스럽게 가리 킵니다.

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

그러나 초기 몇 번의 시도는 실패했습니다.

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

^[^M의해 수득 CtrlVEsc하고 CtrlVEnter, 각각.

그들은 모두 문자를 터미널에 표시했습니다 (원격 세션에 적용하기 전에 로컬에서 테스트했습니다). 인터넷 검색에서 파이썬을 사용하여 의사 터미널 장치에 쓰는 이 SO post를 발견 했습니다 .

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

그리고 대화 형 파이썬 쉘에서 시도해 보았습니다.

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

끝난!


1
파이썬 스크립트는 터미널에 액세스하려면 루트 권한이 필요합니다.
martinkunev

6

실행중인 경우 vim에 명령을 보낼 수 있습니다 ...

Vim 서버

예를 들면 다음과 같습니다.

vim --servername vim

vim이 "vim"이라는 이름의 서버를 시작하게합니다. 두 번 호출하면 새 서버는 "vim1", 세 번 호출하고 "vim2"등이됩니다. 해당 명령의 별명을 만들 수 있습니다.

창 제목을 보면 특정 인스턴스의 서버 이름을 알 수 있습니다. 당신이 볼 때 :

[이름 없음] +-VIM3

서버 이름은 대소 문자를 구분하지 않고 "VIM3"입니다 ( "vim3"은 동일한 인스턴스를 나타냅니다). 다음과 같은 경우에 유의하십시오.

[이름 없음] +-VIM

반드시 "VIM"이라는 서버가 있다는 의미는 아닙니다. 서버 이름을 다음과 같이 나열하여 서버가 존재하는지 확인할 수 있습니다.

vim --serverlist

여전히, 문제는 특히 "VIM"에 대해서만 발생합니다. "GVIM"또는 숫자가 추가 된 다른 이름이 표시되면 이것이 서버임을 의미합니다.

클라이언트를 사용하는 방법

이제 질문에 따라 다음을 수행하여 모두 저장하고 주어진 vim 인스턴스를 종료 할 수 있습니다.

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

삽입 또는 명령 모드에있는 경우 이스케이프를 사용하여 일반 모드로 돌아갑니다. 이외의 다른 작업을 수행 할 수는 :wqa있지만 새 파일 이름이 없기 때문에 저장할 수없는 버퍼의 스왑 파일을 남겨두기 때문에 나에게 가장 적합한 것 같습니다.

여기에서와 같이 모든 인스턴스에 대해 그렇게하려면 서버 목록을 다음과 같이 반복하면됩니다.

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

어떤 이유로 마음에 들지 않으면 --remote-send대신 --remote-expr클라이언트가 결과 또는 그로 인해 발생할 수있는 오류를 출력하도록하는 이점을 사용할 수 있습니다.

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

E141: No file name for buffer 1

Vim의 서버 기능을 사용하려면 Vim을 +clientserver옵션 으로 빌드해야합니다 .


5

reptyr시스템 패키지 관리자를 사용하여 다음과 같은 명령을 설치하십시오 .

sudo apt install reptyr
pacman -Sy reptyr

그런 다음 reptyr명령을 사용하여 다음과 같이 원격 tty를 로컬 (신규) tty로 전환하십시오.

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

명령 출력 PID에서 프로세스 ID는 어디에 있습니까 ps?

오류가 발생하면 :

pid 12345에 첨부 할 수 없음 : 권한 거부

"ptrace 범위"를 0으로 변경하십시오.

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

vim 세션이 이전 세션에서 새 세션으로 교체되면 평소대로 저장하고 종료하십시오. Enter콘솔을 새로 고치려면 을 (를) 눌러야 할 수도 있습니다 .


0

우아하게 Vim을 죽이면 어떨까요?

kill -s 15 -p [PID for Vim]

kill -s (신호) 15는 SIGTERM이라고하며 프로세스가 정상적으로 종료되도록 알려줍니다.

Vim의 PID (프로세스 ID)를 얻으려면 다음을 사용하십시오.
ps ax | grep vim


1
Vim은 전송 된 신호에 상관없이 저장되지 않은 변경 사항을 자동으로 쓰지 않습니다.
muru
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.