シェルコマンドをサイレントに実行する方法は?


70

:!<command>シェルでコマンドを実行するために使用できます。しかし、これは私の端末を「引き継ぎ」、stdoutその特定のコマンドで埋めます。

ゼロ以外の終了コードのみを通知するコマンドをバックグラウンドで実行するにはどうすればよいですか?


1
+ pythonインターフェース、または他の言語インターフェースのいずれかを使用しますか?
joeytwiddle

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ウィンドウが「覆い焼き」になります(try :silent !ls)... 「がtは非0の終了コードに適切な出力を与える...だから私はそれだけで使用するよりも少し関わっだ怖い:silent...
マーティンTournoijに

あ、ごめんなさい。コメントの作成中に、非同期実行に関するメモを追加しました。終了ステータスの問題に対処する方法がわかりません。Freenodeの#vimで試してみてください。
OliverUv

また、Vim 7.4のパッチ1-213を使用したバージョンでは、出力:silent exec "!ls":silent !ls表示もしないことに注意してください。
OliverUv

3
Hmは、ここで私は後に何を得るのです:silent !lsi.stack.imgur.com/1XvS6.png ...私は押す必要が^L...もう一度それを修正するために
マーティンTournoij

vim-dispatchは確かに、与えられた問題の解決策のように見えます。
-joeytwiddle

30

次のようなEnterメッセージをトリガーせずにコマンドを実行するには:

Enterキーを押すか、コマンドを入力して続行します

次の簡単な例を試してください。

: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
ゼロ以外の終了コードで通知を受けるにはどうすればよいですか?
マーティントゥルノイ

1
ゼロ以外の終了コードの解決策ではありませんが、これに追加するために、このサイレントコマンドを使用すると、コマンドを: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

プレビューウィンドウが開きます。代わりにquickfixエラーリストを使用するには:

silent cget /tmp/output | copen

クイックフィックスリストを使用すると、を使用してエラーに簡単に移動できます:cnext。ただしcopen、カーソルが開いたらクイックフィックスウィンドウに移動します。これはおそらく驚くべきことです。

(そのための回避策は:copen、プロセスを最初に開始するときにQFウィンドウを開くことであるため、最後に呼び出す必要ありません。)


2
これは、実際に質問に答える唯一の答えです:「ゼロ以外の終了コードでのみ通知するバックグラウンドでコマンドを実行する」 ...
マーティントゥルノイ

2
彼らは質問のタイトルに完全に答えているので、彼らが賛成票を持っていると信じています。それが訪問者をこのページに導くものです。「シェルコマンドをサイレントモードで実行する方法」一般的なSE現象!訪問者は感謝していますが、おそらく規律はありません。
-joeytwiddle

理想的な世界では、「シェルコマンドをサイレントモードで実行する方法」という2つの質問があります。および「バックグラウンドでシェルコマンドを実行する方法」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変数から次のことが
わかり

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.

これは実際にはバックグラウンドで実行されていません。終了するまで待つ必要があります。
マーティントゥルノイ

@Carpetsmoker:はい、したがって、私のコメントは「…は…のfoo &ようにバックグラウンドプロセスを処理しません。Qテキスト全体から、私はそれをorとして解釈しました。どちらの「外部コマンドAKAの背景として実行」または「バックグラウンド・プロセスとして、外部コマンド_and_として実行してください。」。私は主にQなどのタイトルに基づいて回答し、「わからない…」に関するコメントを追加し、どちらかを明確にするためにOPに残しました。
ルニウム

3

Vim 8ではジョブのサポートが導入されました。プラグインに依存することなく、バックグラウンドで外部コマンドを実行できます。たとえば、現在の場所でマークダウンサーバー(markserv)を実行し、vimセッションをブロックしないようにするには:

:call job_start('markserv .')

これにより、markservプロセスが現在のvimプロセスのサブプロセスとして開始されます。これはで確認でき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 !、大文字を除き、Vimの組み込みコマンドのように見えSます。オプション!を使用して、さらに似ているようにすることもできます。を呼び出すとsystem()、シェルコマンドが本当にサイレントになります。画面のフラッシュや再描画は行われません。

(ステータスコードが必要な場合は、v:shell_error変数を確認できます。詳細についてはヘルプを参照してください)


1

ASYNCRUNのプラグインが、このために設計されている場合、それはあなたがVim8 / NeoVimにバックグラウンドでシェルコマンドを実行するとのQuickFixウィンドウに出力を表示することができます。

!コマンドの代替として:

:AsyncRun ls -la /

また、quickfixウィンドウで出力を完全に非表示にすることもできます。

: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.