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


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.