쉘 명령을 자동으로 실행하는 방법은 무엇입니까?


70

:!<command>쉘에서 명령을 실행하는 데 사용할 수 있습니다. 그러나 이것은 내 터미널을 "인계" stdout하고 특정 명령으로 채 웁니다 .

0이 아닌 종료 코드에서만 나에게 알리는 명령을 백그라운드에서 어떻게 실행합니까?


1
+ python 인터페이스 또는 다른 언어 인터페이스 중 하나를 사용 하시겠습니까?
— joeytwiddle 2012

1
@joeytwiddle 예
— OrangeTux

답변:


52

:silent exec "!command"

명령이 실행되는 동안 vim 세션은 계속 사용됩니다. 이것은 Vim의 동기 특성 때문입니다. CTRL + z를 눌러 (Vim을 백그라운드로 보내려면) 쉘로 돌아간 다음 fg평소 와 같이 명령 으로 vim을 다시 시작할 수 있습니다.

비동기식으로 작업하려면 Tim Pope의 플러그인 vim-dispatch 또는 NeoMake 플러그인을 사용하여 쉽게 활용할 수있는 비동기 명령 실행을 기본적으로 지원하는 프로젝트 NeoVim을 살펴보십시오. Vim의 최신 버전은 비동기 작업도 지원합니다.

: h : silent 참조


5
이것은 또한 내가 질문을 보았을 때 시도한 첫 번째 것입니다 :-) 그러나 stdout (또는 stderr)으로 출력하는 명령을 사용하면 기본 Vim 창을 "복합"합니다 (시도 :silent !ls) ... 0이 아닌 종료 코드에서 적절한 결과를 제공하지 않습니다. 따라서 사용하는 것보다 조금 더 복잡합니다 :silent.
— Martin Tournoij

미안 주석을 쓰는 동안 비동기 실행에 대한 메모를 추가했습니다. 종료 상태 문제를 해결하는 방법을 모릅니다. Freenode에서 #vim을 시도 할 수 있습니다.
— OliverUv 2019

또한 점에 유의도 할 :silent exec "!ls"나 :silent !ls패치 1-213와 빔, 7.4의 내 버전에 전혀 출력을 보여줍니다.
— OliverUv 2019

3
흠, 다음은 내가 얻는 것입니다 :silent !ls: i.stack.imgur.com/1XvS6.png ... ^L다시 고쳐야합니다 ...
— Martin Tournoij

vim-dispatch는 주어진 문제에 대한 해결책처럼 보입니다.
— joeytwiddle

30

Enter 메시지를 트리거하지 않고 명령을 실행하려면 다음과 같이하십시오.

계속하려면 Enter 키를 누르거나 command를 입력하십시오.

다음 간단한 예제를 시도하십시오.

:silent !echo Hello

그런 다음 Vim으로 돌아갈 때 Ctrl+ L(또는 :redraw!)를 눌러 화면을 새로 고칩니다.

새로 고침이 필요하지 않도록 다음과 같이 사용자 정의 명령을 정의 할 수 있습니다.

:command! -nargs=1 Silent execute ':silent !'.<q-args> | execute ':redraw!'

이제 새로운 Vim 명령을 사용하여 쉘 명령을 실행할 수 있습니다 (참고 : ! 없이 대문자 S 사용 ).

:Silent ps

출처 : Vim Wikia 사이트에서 "계속하려면 Enter 키를 누르십시오"메시지가 표시되지 않음


1
0이 아닌 종료 코드에 대한 알림을 받으려면 어떻게합니까?
— Martin Tournoij

1
0이 아닌 종료 코드에 대한 솔루션은 아니지만 여기에 추가하기 위해이 Silent 명령을 사용 :Silent ctags -R . > /dev/null &하면 백그라운드에서 명령 을 실행할 수 있습니다 . stdout을 / dev / null로 보내면 출력이 vim 버퍼에 나타나지 않습니다.
— ftvs

10

빠르고 더러운 솔루션 (순수한 Vimscript)

백그라운드에서 프로세스를 시작할 수 있습니다.

:!slow_command_here > /tmp/output 2>&1 &

그러나 Vim은 프로세스가 언제 완료되었는지, 어떻게 마커 파일을 사용하는지 알아낼 방법이 필요합니다.

:!(rm -f /tmp/finished; slow_command_here > /tmp/output 2>&1; echo "$?" > /tmp/finished) &

이제 Vim에게 프로세스가 완료되었는지 여부를 자주 확인하도록 요청할 수 있습니다.

:augroup WaitForCompletion
:autocmd!
:autocmd CursorHold * if filereadable('/tmp/finished') | exec "augroup WaitForCompletion" | exec "au!" | exec "augroup END" | echo "Process completed with exit code ".readfile('/tmp/finished')[0] | end
:augroup END

이봐, 예쁘지 않지만 일종의 작동합니다!

단점

불행히도 위의 autocmd는 커서를 움직일 때까지 트리거되지 않습니다. 한 번에 둘 이상의 백그라운드 프로세스를 실행하려면 해당 파일과 autocmd 그룹 이름에 고유 ID를 추가해야합니다.

따라서 추가 종속성을 처리 할 수 ​​있으면 다른 답변에서 언급 한 vim-dispatch 플러그인과 같은 시도되고 테스트 된 솔루션을 사용하는 것이 좋습니다.

출력 표시

종료 코드가 아닌 프로세스 출력 을 보려면 위 의 마지막을 다음으로 바꾸십시오 .echo

silent botright pedit /tmp/output

미리보기 창이 열립니다. 빠른 수정 오류 목록을 대신 사용하려면

silent cget /tmp/output | copen

빠른 수정 사항 목록을 사용하면을 사용하여 오류를 쉽게 탐색 할 수 있습니다 :cnext. 그러나 copen커서가 열릴 때 빠른 수정 창으로 커서를 이동하면 놀랍고 성 가실 것입니다.

(이를위한 해결책 :copen은 프로세스를 처음 시작할 때 QF 창을 여는 것이므로 마지막에 호출 할 필요 가 없습니다 .)


2
이것은 실제로 질문에 대답하는 유일한 대답입니다 : "제로가 아닌 종료 코드에서만 나에게 알리는 명령을 백그라운드에서 실행하십시오 ... " 왜 다른 답변이 공감대를 갖는지 전혀 모르겠습니다 ...
— Martin Tournoij

2
질문의 제목 에 완벽하게 답변 하여이 페이지에 방문자를 유도하기 때문에 공감대가 있다고 생각 합니다. "쉘 명령을 자동으로 실행하는 방법?" 일반적인 SE 현상! 방문객들은 감사하지만 징계되지는 않을 것입니다.
— joeytwiddle

이상적인 세계에서는 아마도 "쉘 명령을 자동으로 실행하는 방법"이라는 두 가지 별도의 질문이있을 것입니다. "백그라운드에서 쉘 명령을 실행하는 방법?" Google 직원이 원하는 것을 찾을 수 있도록
— joeytwiddle

6

백그라운드에서 명령 실행

나는 조금 막는 명령을 실행하고 있었고 실제로 출력에 신경 쓰지 않았습니다. 이것은 터미널 / 에뮬레이터가 아닌 시스템에 연결된 프로세스를 시작하고 모든 출력을 / dev / null로 리디렉션하여 처리 할 수 ​​있습니다. 예를 들면 다음과 같습니다.

:silent exec "!(espeak 'speaking in background'&) > /dev/null"

는 (...&)배경에서 그것을 실행하고 > /dev/null모든 출력 리디렉션 /dev/null(아무것도).

괄호는 출력을 서브 쉘 (또는 이와 유사한 것)에 트랩하지만 현재 쉘에 첨부되지 않은 부작용이 있습니다 (대부분은 아님).

매핑을 사용하여 백그라운드에서 자동으로 명령 실행

방금 당신 이 실제로 그것을 매핑하면 다음과 같은 것을 할 수 있음을 깨달았습니다.

nnoremap <silent> <leader>e :!$(espeak 'speaking in the background'&) > /dev/null

위의 명령 표시 줄에는 아무것도 표시되지 않으며 vim 외부의 터미널에는 아무것도 표시되지 않습니다. 에 매핑 될 것 <leader> e이다, \ e기본적으로.

명령 실행, 출력 캡처, 내용 표시

(또 다른 편집-아마도 가장 작은 편집). 이 사람은 것이다 표시 출력 당신이 그렇게 선택하면 명령의를 :


새로운 탭 내부 :

silent exec "!(echo 'hello. I'm a process! :)') > /tmp/vim_process" | :tabedit /tmp/vim_process

수직 스플릿 내부 :

silent exec "!(echo 'hello. I'm a process :)') > /tmp/vim_process" | :vs /tmp/vim_process

수평 분할 내부 :

silent exec "!(echo 'hello. I'm a process :)') > /tmp/vim_process" | :sp /tmp/vim_process

... 너가 원하는 것을해라


5

종료 코드에 신경 쓰지 않으면 다음과 같이 할 수 있습니다.

:call system('/usr/bin/zathura using-docker.pdf &')

1
종료 코드에 관심이 있다면 v:shell_error변수가 알려줄 것입니다.
— Jerome Dalbert

4

이것이 귀하의 요구에 맞는지 확실하지 않지만 (백그라운드 프로세스를에서와 같이 처리하지 않고 foo & – "백그라운드에서"의 의미인지 확실하지 않음 ), 다음과 같이 사용자 정의 명령을 사용할 수 있습니다.

fun! s:PraeceptumTacet(cmd)
    silent let f = systemlist(a:cmd)
    if v:shell_error
        echohl Error
        echom "ERROR #" . v:shell_error
        echohl WarningMsg
        for e in f
            echom e
        endfor
        echohl None
    endif
endfun

command! -nargs=+ PT call s:PraeceptumTacet(<q-args>)

그런 다음 예를 들어 사용하십시오.

:PT ls -l
:PT foobar
ERROR #127
/bin/bash: foobar: command not found

오류 메시지가 필요하지 않거나 간단한 메시지 만 system()있으면 충분할 수 있습니다 ( v:shell_error예 :) echo Error!.

에서 도움 V : shell_error :

                                        v:shell_error shell_error-variable
v:shell_error   Result of the last shell command.  When non-zero, the last
                shell command had an error.  When zero, there was no problem.
                This only works when the shell returns the error code to Vim.
                The value -1 is often used when the command could not be
                executed.  Read-only.
                Example: >
    :!mv foo bar
    :if v:shell_error
    :  echo 'could not rename "foo" to "bar"!'
    :endif
                "shell_error" also works, for backwards compatibility.

이것은 실제로 백그라운드에서 실행되지 않습니다. 여전히 완료 될 때까지 기다려야합니다.
— Martin Tournoij

@Carpetsmoker : 그렇습니다. 따라서 “…는 foo &…… 에서와 같은 백그라운드 프로세스를 처리하지 않습니다 . Q 텍스트 전체에서 나는 그것을 또는로 해석했습니다. “외부 명령 AKA 배경으로 실행 ” 또는 “백그라운드 프로세스로 외부 명령 _and_로 실행 ” 중 하나 입니다. 나는 주로 Q 등의 제목을 바탕으로 답변을했으며 “잘 모르겠 음…” 에 대한 의견을 추가했습니다 .
— Runium

3

Vim 8은 채용 지원을 도입했습니다. 플러그인에 의존하지 않고 백그라운드에서 외부 명령을 실행할 수 있습니다. 예를 들어, vim 세션을 차단하지 않고 현재 위치에서 markdown 서버 ( markserv ) 를 실행하려면 다음을 수행하십시오 .

:call job_start('markserv .')

이것은 현재 vim 프로세스의 하위 프로세스로 markserv 프로세스를 시작합니다. 로 확인할 수 있습니다 pstree.

job_start 참조


2

다음 코드를 사용합니다.

command! -nargs=1 Silent call SilentExec(<q-args>)

function! SilentExec(cmd)
  let cmd = substitute(a:cmd, '^!', '', '')
  let cmd = substitute(cmd, '%', shellescape(expand('%')), '')
  call system(cmd)
endfunction

이제 다음을 입력 할 수 있습니다

:Silent !your_command

이것은 silent !capital을 제외하고 Vim의 내장 명령 과 거의 같습니다 S. 심지어 옵션 !이 더 비슷하게 보이도록 할 수도 있습니다. system()쉘 명령을 진정으로 조용하게하는 호출 : 화면이 깜박이지 않고 다시 그리기가 없습니다.

(상태 코드가 필요한 경우 v:shell_error변수를 확인할 수 있습니다. 자세한 내용은 도움말을 참조하십시오)


1

AsyncRun의 이 용으로 설계된 경우 플러그인은, 당신이 Vim8 / NeoVim에서 백그라운드에서 쉘 명령을 실행하고 quickfix 창에 출력을 표시 할 수 있습니다.

!명령 대신

:AsyncRun ls -la /

빠른 수정 창에서 출력을 완전히 숨길 수도 있습니다.

:AsyncRun -mode=3 ls -la /

작업이 완료되면 AsyncRun은 옵션을 전달하여 알려줍니다 -post.

:AsyncRun -post=some_vim_script   ls -la /

에 의해 정의 된 vim 스크립트 -post는 작업 완료 후 실행됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.