Как выполнить команды оболочки без вывода сообщений?

70

:!<command>может использоваться для выполнения команды в оболочке. Но это «захватывает» мой терминал и наполняет его stdoutименно этой командой.

Как выполнить команду в фоновом режиме, которая уведомляет меня только о ненулевом коде выхода?

OrangeTux
источник
1
Хотели бы вы использовать интерфейс + python или один из других языковых интерфейсов?
Joeytwiddle
1
@joeytwiddle Да
OrangeTux

Ответы:

52

:silent exec "!command"

Обратите внимание, что ваша сессия vim все еще будет занята во время выполнения вашей команды. Это связано с синхронным характером Vim. Вы все еще можете вернуться к своей оболочке, нажав CTRL + z (чтобы отправить Vim в фоновый режим), а затем возобновить работу vim с помощью команды, fgкак обычно.

Чтобы сделать все асинхронно, взгляните на плагин Tim Pope vim-dispatch или проект NeoVim, который имеет встроенную поддержку асинхронного выполнения команд, которую вы легко можете использовать с помощью плагина NeoMake. Последняя версия Vim также поддерживает асинхронные задачи.

Смотри : h: тихий

OliverUv
источник
5
Это также первое, что я попробовал, когда увидел вопрос :-) Но если вы используете команду, которая выводит в stdout (или stderr), она "забьет" ваше главное окно Vim (попробуйте :silent !ls) ... Это также не не дает правильного вывода для кода выхода, отличного от 0 ... Так что я боюсь, что это немного сложнее, чем просто использование :silent...
Мартин Турной
Ой, извини. Добавлены некоторые заметки об асинхронном выполнении, пока вы пишете свой комментарий. Не знаю, как решить проблему статуса выхода. Возможно, вы захотите попробовать в #vim на Freenode.
OliverUv 19.02.15
Я также хочу отметить , что ни один, :silent exec "!ls"ни :silent !lsпоказать никакого вывода вообще на моей версии Vim, 7.4 с патчами 1-213.
OliverUv 19.02.15
3
Хм, вот что я получаю после :silent !ls: i.stack.imgur.com/1XvS6.png ... Мне нужно нажать, ^Lчтобы исправить это снова ...
Мартин Турной
vim-dispatch, безусловно, выглядит как решение данной проблемы.
Joeytwiddle
30

Чтобы выполнить команду без запуска сообщения Enter, например:

Нажмите клавишу ВВОД или введите команду, чтобы продолжить

попробуйте следующий простой пример:

:silent !echo Hello

Затем нажмите Ctrl+ L(или :redraw!), чтобы обновить экран, когда вернетесь к Vim.

Чтобы избежать необходимости обновления, вы можете определить свою собственную команду, например:

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

Теперь вы можете использовать новую команду Vim для запуска команды оболочки (примечание: без ! И с заглавной буквы S ):

:Silent ps

Источник: Избегайте подсказок «Нажмите ENTER, чтобы продолжить» на сайте Vim Wikia

kenorb
источник
1
Как вы получаете уведомление о ненулевом коде выхода?
Мартин Турной
1
Не решение с ненулевым кодом завершения, но, чтобы добавить к этому, эта команда 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.

Поэтому, если вы можете справиться с дополнительной зависимостью, вам может быть лучше использовать проверенное решение, такое как плагин vim-dispatch, упомянутый в другом ответе.

Отображение вывода

Если вы хотите увидеть выходные данные процесса, а не просто код выхода , замените последний результат echoна:

silent botright pedit /tmp/output

Это откроет окно предварительного просмотра. Чтобы использовать список ошибок быстрого исправления вместо:

silent cget /tmp/output | copen

Список быстрых исправлений позволяет легко переходить к ошибкам с помощью :cnext. Однако при его copenперемещении курсор в окно быстрого исправления открывается, что, вероятно, будет удивительно / раздражающим.

(Обходным путем для этого может быть открытие окна QF :copenпри первом запуске процесса, поэтому вам не нужно будет вызывать его в конце.)

joeytwiddle
источник
2
Это единственный ответ, который на самом деле отвечает на вопрос: «выполнить фоновую команду, которая уведомляет меня только о ненулевом коде выхода» ... Я понятия не имею, почему у других ответов вообще есть отклики ...
Мартин Турной
2
Я полагаю, что у них есть положительные отзывы, потому что они прекрасно отвечают на заголовок вопроса, который и приводит посетителей на эту страницу. "Как выполнять команды оболочки без вывода сообщений?" Обычный феномен SE! Посетители благодарны, но, возможно, не дисциплинированы.
Joeytwiddle
В идеальном мире у нас, вероятно, было бы два отдельных вопроса: «Как выполнять команды оболочки без вывода сообщений?» и "Как выполнять команды оболочки в фоновом режиме?" чтобы гуглеры могли найти то, что ищут.
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по умолчанию.

Выполнение команды, захват ее вывода, отображение ее содержимого

(Другое редактирование - и, возможно, самое последнее). Это один будет отображаться на выходе из команды , если вы так выбираете:


ВНУТРИ НОВОГО TAB:

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

... делай что хочешь

dylnmc
источник
5

Если вам не важен код выхода, вы можете пойти с этим:

:call system('/usr/bin/zathura using-docker.pdf &')
hsnotebook
источник
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.
Runium
источник
Это на самом деле не работает в фоновом режиме; вам все еще нужно дождаться его окончания.
Мартин Турной
@Carpetsmoker: Да, поэтому мой комментарий «… не обрабатывает фоновые процессы, как в foo &…» . Из текста Q в целом я истолковал его как либо либо, либо. Либо «Выполнить как внешняя команда AKA фон», либо «Выполнить как внешняя команда _and_ как фоновый процесс» . Я отвечал в основном на основе названия Q и т. Д. - и добавил комментарий «Не уверен…» - и оставил это на OP, чтобы уточнить, если либо, либо.
Runium
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 /

Вы также можете полностью скрыть вывод в окне быстрого исправления:

:AsyncRun -mode=3 ls -la /

Когда работа будет завершена, AsyncRun уведомит вас, передав опцию -post:

:AsyncRun -post=some_vim_script   ls -la /

Сценарий vim, определенный с помощью, -postбудет выполнен после завершения задания.

skywind3000
источник