xargs и vi - “Вход не от терминала”

Ответ больше имеет отношение к истории условий, чем их фактическое значение.

В первые годы терминалы были устройствами, как DEC VT101, у меня есть нахождение в моем гараже.:-)

Эмуляторы терминала прибыли позже. Я не знаю то, что было на первом месте, но теперь у нас есть несколько различных видов эмуляторов терминала.

  • Которые набирают в удаленную систему и эмулируют терминал (HyperTerminal, minicom, и т.д.)
  • Которые соединяются по сети (telnet, и т.д.) и эмулируют аппаратный терминал (x3270 и tn5250 придите на ум),
  • Которые соединяются с локальным pseudo-tty (xterm, rxvt, и т.д.)

Я предполагаю, что терминал, сидящий рядом с компьютером, упоминался как консоль в первые годы, но позже который прибыл для значения клавиатуры и монитора, подключенного к компьютеру. На Linux, по крайней мере, исторически только была одна консоль (Ваша видеокарта и монитор, объединенный с приложенными клавиатурами и мышами), но у нас были виртуальные консоли, которые позволяют нам переключаться от одной "консоли" до другого на одной консоли. (/dev/console и /dev/tty0 укажите на одну основную консоль.)

14
31.07.2012, 23:52
7 ответов
vi $(locate php.ini)

Примечание: это будет иметь проблемы, если Ваши пути к файлам будут иметь пробелы, но это функционально эквивалентно Вашей команде.
Эта следующая версия правильно обработает пробелы, но немного более сложна (новые строки в именах файлов все еще повредят ее хотя),

(IFS=$'\n'; vi $(locate php.ini))


Объяснение:

То, что происходит, - то, что программы наследовали свои дескрипторы файлов от процесса, который породил их. xargs имеет его STDIN, подключенный к STDOUT locate, так vi не имеет никакой подсказки что исходный STDIN действительно в.

12
27.01.2020, 19:50
  • 1
    xargs замечателен, один из моих любимых инструментов - ему просто не удовлетворяют для использования с программами, которые используют stdin для чего-либо кроме канала данных. мне нравятся Ваш ответ и Ваше объяснение кроме этого, таким образом, +1 так или иначе :) –  cas 01.08.2012, 01:16
  • 2
    @CraigSanders мне не нравится он, потому что слишком легко злоупотребить (использование неправильно) и закончить тем, что повредилось. Я никогда не сталкивался ни с чем, что я должен был абсолютно использовать xargs поскольку это не могло быть сделано непосредственно с оболочкой (или find). Однако я могу думать о случаях, где это было бы лучшее решение. Так, пока Вы понимаете что xargs делает, как это разделяет аргументы, как это запускает программу, и т.д., и использует его правильно, я сказал бы, идут для него, обратные галочки :-P –  Patrick 01.08.2012, 01:23
  • 3
    это не может быть разбито для вещей как ... | awk '{print $3}' | xargs | sed -e 's/ /+/g' | bc (для складывания всех значений поля 3). или с sed -e 's/ /|/g' для построения regexp. и да, как любой инструмент, действительно необходимо знать, как использовать его и каковы его ограничения и протесты. –  cas 01.08.2012, 01:29

Этот вопрос ранее задали на форуме Суперпользователя.

Заключение в кавычки из ответа @grawity по тому вопросу:

При вызове программы через xargs stdin программы (стандартный вход) указывает на/dev/null. (Так как xargs не знает исходный stdin, он делает следующую лучшую вещь.)

Vim ожидает, что его stdin совпадет с его терминалом управления и выполняет различный связанный с терминалом ioctl's на stdin непосредственно. При выполнении на/dev/null (или любой non-tty дескриптор файла), те ioctls бессмысленны и возвращают ENOTTY, который тихо проигнорирован.

Это упоминается в страницах руководства для xarg. От OSX/BSD:

- o Вновь открыли stdin как/dev/tty в дочернем процессе прежде, чем выполнить команду. Это полезно, если Вы хотите, чтобы xargs запустил интерактивное приложение.

Следовательно, на OSX, Вы могли использовать следующую команду:

find . -name "php.ini" | xargs -o vim

В то время как, нет никакого прямого переключателя на версии GNU, эта команда будет работать. (Удостоверьтесь, что включали dummy строка, иначе это отбросит первый файл.)

find . -name "php.ini" | xargs bash -c '</dev/tty vim "$@"' dummy

Вышеупомянутыми решениями является любезность Jaime McGuigan на SuperUser. Добавление их здесь для любых будущих посетителей, ищущих сайт эту ошибку.

10
27.01.2020, 19:50
  • 1
    +1 спасибо за подсказку по-o. я использовал xargs в течение многих лет и никогда не замечал, что.... просто проверил страницу справочника в моей системе, поэтому это не GNU xargs функция. Страница справочника действительно обеспечивает xargs sh -c 'emacs "$@" < /dev/tty' emacs поскольку то, чего они требуют, является более гибкой и портативной альтернативой (хотя это довольно забавно для GNU, чтобы быть, предпочитают мобильность функциям :). –  cas 01.08.2012, 01:22

Быстрый способ сделать это состоит в том, чтобы использовать обратные галочки (иначе серьезные диакритические знаки) для выполнения команды до другого выполнения команды.

Например.

vi `find / -type f -name 'php.ini'`

Команда, содержавшая в обратных галочках, выполнится сначала. Вывод содержавшей команды затем выполняется командой, указанной перед обратными галочками.

Например, в строке выше, find / -type f -name 'php.ini' команда выполнится сначала, отправить вывод, и затем vi будет выполняться на том выводе.

0
27.01.2020, 19:50
  • 1
    слишком легко перепутаны для одинарных кавычек. использовать $(find ...) вместо этого. –  cas 01.08.2012, 01:24
  • 2
    предполагая это также повредится на пробелах и/или новых строках в именах файлов? –  cwd 01.08.2012, 15:08
  • 3
    Это - то, как Вы выполняете команды оболочки в сценариях удара. У меня ничего никогда не было повреждение на пробелах или новых строках в моих сценариях или при использовании его в одном лайнере. Однако я никогда не пытался открыть несколько файлов в vi использование этого метода. Довольно возможно, что это могло повредиться на новых строках или пробелах, в зависимости от как vi читает и выполняет вывод. –  tacotuesday 08.08.2012, 09:07

Отредактировать несколько php.ini в том же редакторе?

Попытка: vim -o $(locate php.ini)

0
27.01.2020, 19:50

Эта ошибка возникает, когда вызывается vim и он подключен к выходу предыдущего конвейера, а не к терминалу и получает другой неожиданный ввод (например, NUL). то же самое происходит, когда вы запускаете: vim , поэтому в этом случае помогает команда reset . Это хорошо объясняется грубостью суперпользователя .

В Unix / OSX вы можете использовать xargs с параметром -o , например:

locate php.ini | xargs -o vim

-o Повторно открыть stdin как / dev / tty в дочернем процессе перед выполнение команды. Это полезно, если вы хотите, чтобы xargs запускал интерактивное приложение.

В Linux попробуйте следующее обходное решение:

locate php.ini | xargs -J% sh -c 'vim < /dev/tty $@'

В качестве альтернативы используйте GNU parallel вместо xargs , чтобы принудительно выделить tty, например:

locate php.ini | parallel -X --tty vi

Примечание: parallel в Unix / OSX не будет работать, так как имеет другие параметры и не поддерживает tty.

Многие другие популярные команды также обеспечивают выделение псевдо-tty (например, -t в ssh ), поэтому обратитесь за помощью.

В качестве альтернативы используйте find , чтобы передать имена файлов для редактирования, поэтому не нужно xargs , просто используйте -exec , например:

find /etc -name php.ini -exec vim {} +
0
27.01.2020, 19:50

Взлом @Patrick IFSнеобходим только для тупых оболочек, таких как bashи zsh. fishпо умолчанию разбивает строку на новые строки.

$ vim (locate php.ini)

И да поможет нам всем Бог, если хотя бы у одного из нас действительно есть файл с новой строкой в ​​имени. После 17 лет использования Linux я ни разу его не видел. Я бы побеспокоился о поддержке имен файлов с символами новой строки только для сценариев, которые должны работать несмотря ни на что, но такие сценарии, вероятно, не запускают vim в интерактивном режиме.

0
27.01.2020, 19:50

С GNU findutilsи оболочкой с поддержкой замены процесса (ksh, zsh, bash )вы можете сделать:

xargs -r0a <(locate -0 php.ini) vi

Идея заключалась в том, чтобы передать список файлов через -a filename, а не стандартный ввод. Использование -0гарантирует, что он работает независимо от того, какие символы или не -символы могут содержаться в именах файлов.

С помощью zshможно сделать:

vi ${(0)"$(locate -0 php.ini)"}

(где 0— флаг расширения параметра для разделения на NUL ).

Однако обратите внимание, что, в отличие от xargs -r, по-прежнему выполняется viбез аргументов, если файл не найден.

3
27.01.2020, 19:50

Теги

Похожие вопросы