Як виконувати команди оболонки мовчки?


70

:!<command>може використовуватися для виконання команди в оболонці. Але це "переймає" мій термінал і заповнює його stdoutсаме цією командою.

Як виконати команду у фоновому режимі, яка повідомляє мене лише про ненульовий код виходу?


1
Чи бажаєте ви використовувати інтерфейс + python або інший інтерфейс мови?
joeytwiddle

1
@joeytwiddle Так
OrangeTux

Відповіді:


52

:silent exec "!command"

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

Щоб робити справи асинхронно, погляньте на vim-dispatch плагіна Тіма Попа або проект NeoVim, який має вбудовану підтримку для асинхронного виконання команд, яку ви можете легко використовувати за допомогою плагіна NeoMake. Остання версія Vim також має підтримку асинхронних завдань.

Див . : h: мовчати


5
Це також перше, що я спробував, коли побачив запитання :-) Але якщо ви використовуєте команду, яка виводить stdout (або stderr), вона буде "клобувати" ваше головне вікно Vim (спробуйте :silent !ls) ... Це також не робить Я не даю належного виводу на код виходу без 0 ... Тому я боюся, що це трохи більше, ніж просто використання :silent...
Martin Tournoij

Ой, вибачте. Додавши кілька приміток про асинхронне виконання під час написання коментаря. Не знаєте, як вирішити проблему статусу виходу. Ви можете спробувати #vim на Freenode.
OliverUv

Я також хочу зазначити, що ні в моїй версії Vim, 7.4, ні з патчами 1-213 ні в якому разі :silent exec "!ls"не :silent !lsвідображається жоден вихід
OliverUv

3
Гм, ось що я отримую після :silent !ls: i.stack.imgur.com/1XvS6.png ... Мені потрібно натиснути, ^Lщоб виправити це знову ...
Мартін Турной

vim-dispatch, безумовно, виглядає як вирішення даної проблеми.
joeytwiddle

30

Для виконання команди без запуску повідомлення Enter, наприклад:

Натисніть 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


1
Як ви отримуєте сповіщення про ненульовий код виходу?
Martin Tournoij

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при первинному запуску процесу, тому вам не потрібно буде називати його в кінці.)


2
Це єдина відповідь, яка насправді відповідає на питання: "виконайте команду у фоновому режимі, яка сповіщає мене лише про ненульовий код виходу" ... Я поняття не маю, чому в інших відповідях взагалі є додаткові кошти ...
Мартін Турноїй

2
Я вважаю , що вони мають upvotes , тому що вони чудово відповісти на назву питання, що і призводить відвідувачів на цій сторінці. "Як беззвучно виконувати команди оболонки?" Поширене явище 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за замовчуванням.

Запуск команди, захоплення її результату, показ його вмісту

(Ще одна редакція - і, можливо, найновіша). Це один буде відображатися на виході з команди , якщо ви так вибираєте:


ВНУТРИ НОВИЙ ТАБЛИЦЯ

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.

Це насправді не працює у фоновому режимі; ще потрібно дочекатися його закінчення.
Martin Tournoij

@Carpetsmoker: Так, таким чином мій коментар "... не обробляє фонові процеси, як у foo &..." . З тексту Q в цілому я трактував це як або. Або "Виконати як зовнішню команду AKA background", або "Виконати як зовнішню команду _and_ як фоновий процес" . Я відповідав головним чином на основі назви Q тощо - і додав коментар до “Не впевнений…” - і залишив це ОП, щоб уточнити, чи є, чи.
Руніум

3

Vim 8 представив підтримку робочих місць. Можна виконувати зовнішню команду у фоновому режимі, не покладаючись на плагіни. Наприклад, запустити сервер розмітки ( markserv ) у поточному місці та не блокувати сеанс vim:

:call job_start('markserv .')

Це запускає процес markserv як підпроцес поточного процесу vim. Ви можете підтвердити це за допомогою pstree.

Дивіться роботу_стар


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буде виконаний після завершення завдання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.