Термінал прихистився після виклику Vim з xargs


30

Я іноді намагався викликати Vim за допомогою xargsтакого:

find . -name '*.java' | xargs vim

… Які твори:

  1. Коли Vim запускається, я коротко бачу такий попереджувальний спалах:

    Vim: Warning: Input is not from a terminal
    
  2. Працює редагування - :filesправильно перелічує всі .javaфайли, як очікувалося.
  3. Я можу зберегти і вийти.

Однак після виходу з Vim мій термінал працює:

  • Що б я не набрав у запиті оболонки, це не відлунне.
  • Повернення перевезення взагалі не відображаються, а канали рядків відображаються лише іноді.

Це триває, поки я reset(1)не видаю команду повторно ініціалізувати термінал.

Це помилка Vim, чи є більш задовільне пояснення того, чому він взаємодіє з терміналом так? Я бачив, як це відбувається на Vim до версії 7.3 (версія, здається, не має значення) в Linux та різних Unices.

Мені відомо одне вирішення, а саме vim $(find . -name '*.java'). Інші способи подолання будуть вітатися, хоча це не моє головне питання.


Мені подобається ваше бажання поповнити цей сайт якомога більше запитань, але ... на це запитання відповіли десятки разів протягом років у SO / SU та інших місцях: xargsвикористовує манекен, stdinякий не може бути використаний Vim та перерви все згодом.
romainl

1
@romainl Я не активний на цих сайтах, і я ніколи не бачив, щоб його там запитували - чесно.
200_успіх

Супутнє: superuser.com/questions/336016/… - можливо, хтось може звести кращі відповіді на чудову відповідь.
муру

2
Чудове запитання - таке траплялося зі мною неодноразово. Крім того, я не використовую жодних інших сайтів SO - якщо це пов’язано з VIM, я хотів би знайти його тут.
craigp

Відповіді:


21

Це відбувається, коли викликається vim і він підключений до виходу попереднього конвеєра, а не до терміналу і отримує різні неочікувані входи (наприклад, NUL). Те саме відбувається під час запуску:, vim < /dev/nullтому resetкоманда в цьому випадку допомагає. Це добре пояснюється високою популярністю у суперпользователя .

Якщо ви використовуєте findдля передавання імен файлів для редагування, вам не потрібно xargs, просто використовуйте -exec, наприклад:

find . -name '*.java' -exec vim {} +

Якщо ви хочете використовувати xargs, на Unix / macOS слід використовувати -oпараметр, наприклад:

find . -name '*.java' | xargs -o vim

-oПовторно відкрийте stdin як / dev / tty в дочірньому процесі перед виконанням команди. Це корисно, якщо ви хочете, щоб xargs запустив інтерактивну програму.

або:

find . -name "*.java" -type f -print0 | xargs -o -0 vim

Примітка. Використання -print0/ -0підтримка назви файлів з пробілами.


find+ BSDxargs

У Unix / macOS ви можете спробувати наступне вирішення:

find . -name '*.java' | xargs -J% sh -c 'vim < /dev/tty $@'

Ви також можете використовувати синтаксис заміни команд , наприклад:

vim $(find . -name '*.java')
vim `find . -name '*.java`

Альтернативно, використовуйте GNU parallelзамість xargsпримусового виділення tty, наприклад:

find . -name '*.java' | parallel -X --tty vi

Примітка: parallelна Unix / OSX не працюватиме, оскільки він має різні параметри і не підтримує tty.

Багато інших популярних команд також забезпечує розподіл псевдо-tty (як -tу ssh), тому зверніться за допомогою.

Інша пропозиція буде використовувати:

Пов'язані:


Мій GNU xargsне має -J. Здається, це варіант MacOS (BSD), який не присутній у версії GNU.
Призупинено до подальшого повідомлення.

12

Приблизна пропозиція: використовувати буфер як навігатор файлової системи

За допомогою vim -команди прочитайте список шляхів від stdin. Vim's :help --пояснює це: 1

Почніть редагувати новий буфер, який заповнюється текстом, який читається з stdin. Команди, які зазвичай читаються зі stdin, тепер будуть читатися із stderr. Приклад:

find . -name "*.c" -print | vim -

Потім можна використовувати gfабо Ctrl-wCtrl-fпереходити до файлу в тому ж буфері або в новому розділеному вікні відповідно.

Обхідна пропозиція: список аргументів

Ще один чудовий спосіб - використовувати список аргументів Vim. :argadd **/*.javaКоманда буде заповнювати список аргументів Vim з усіма Java - файлів , знайдених всередині поточного каталогу рекурсивно. Потім ви можете використовувати :nextі :prevдля переміщення між файлами.


1 Перший -повідомляє Vim, що ви хочете шукати довідку для параметра командного рядка, другий - це фактично прапор командного рядка, який ви шукаєте. Прочитайте :help help-contextбільше подібних хитрощів.


8

Крім того reset, ви можете спробувати:

stty sane

що також знову зробить ваш термінал придатним.

Пояснення тут див . І якимось чином це можна вважати неправильним поведінкою, принаймні, у Неовіма цього питання немає.


Це точно не відповідає на питання, але це допомогло мені, тому +1.
Відновіть Моніку iamnotmaynard

Це відповідає на моє запитання;) Хоча після прочитання програми ще я думаю, що resetтеж.
Шрідхар Сарнобат

1

Причина полягає в тому, що xargsнабори stdinдля /dev/null, в той час як vimпотреби stdinбути /dev/tty.


xargsРішення BSD (наприклад, Mac):

echo -e 'file1\nfile2' | xargs -o vim

-oвстановлює stdinдочірні процес xarg ( vimв даному випадку) на dev/tty.


xargsРішення GNU (наприклад, Linux):

У ГНУ xargsнемає -oможливості. Натомість вам доведеться скористатися більш складним способом вирішення. (Примітка. Дуже важливо мати кінцевий zeroрядок, не забувайте його.)

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

Ви також можете зробити його псевдонімом:

alias vimin='xargs bash -c '\''</dev/tty vim "$@"'\'' zero'
echo -e 'file1\nfile2' | vimin

Детальне пояснення рішення GNU xargs

Давайте розбимо його крок за кроком:

echo -e 'file1\nfile2' | xargs bash -c '</dev/tty vim "$@"' zero

1. xargsпросто додає stdinдо кінця рядка, тому xargsбуде виконано це:

    bash -c '</dev/tty vim "$@"' zero file1 file2

2. Формат для bash -cє bash -c 'COMMAND_STRING' $0 $1 $2 etc.

"$@"розширюється до позиційних параметрів "$1", "$2"тощо. Він не включає "$ 0", тому що це спеціальний параметр для імені сценарію, а не позиційний параметр. Ось чому нам потрібно додати макетну рядок zero(це може бути будь-яка рядок), щоб зайняти місце $0. В іншому випадку ви втратите перший файл.

Отже, після розширення "$@", ви закінчите:

    bash -c '</dev/tty vim file1 file2' 

3. bash -cвиконає COMMAND_STRING:

    </dev/tty vim file1 file2 

</dev/ttyвстановлює stdinдля /dev/ttyтак , що vimможе працювати в інтерактивному режимі.


+1 Здається, це дублікат відповіді з найбільшою кількістю голосів, але це не так. $0Заповнювач (тут «нуль») є ключовим.
Призупинено до подальшого повідомлення.

0

Я знайшов відсутність усіх цих відповідей. Після боротьби з проблемою xargs, найпростіший спосіб - для мене! - зробити ці пошукові та відкриті в загальному вікні наступний:

vim -O `grep -lir mySearchTerm *`

У мене немає проблеми , використовуючи findз xargsі grep, але я вважаю , що синтаксис дратує. І як щоденний кодер, який використовує vimі термінал як свою IDE, і постійно шукає файли для властивостей, це я і використовую.

Є час і місце для find . -path ./node_modules -prune -o -name '*.js' | xargs grep -i mySearchTermпоєднання з відкриттям файлів через vim та іншими методами. Для мене це рідко.

Сподіваюся, що це комусь допоможе.


2
FWIW рекомендується не використовувати застарілі нотації зворотних посилань і використовувати $(...)замість цього. Це не так важливо у вашому командному рядку, як у сценарії, але я думаю, що все-таки краще використовувати це у своїх відповідях :) (посилання тут і тут )
statox
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.