xargs с командой, что открытый редактор оставляет оболочку в странном состоянии - PullRequest
14 голосов
/ 04 октября 2010

Я попытался создать псевдоним для фиксации нескольких разных проектов git. Я пробовал что-то вроде

cat projectPaths | \
xargs -I project git --git-dir=project/.git --work-tree=project commit -a

где projectPaths - это файл, содержащий пути ко всем проектам, которые я хочу зафиксировать. Похоже, это работает по большей части, запуская последовательно vi для каждого проекта, чтобы я мог написать для него сообщение о коммите. Я, однако, получаю сообщение:

"Vim: Предупреждение: вход не от терминала"

и после этого мой терминал странный: он не показывает текст, который я набираю, и, кажется, не выводит никаких новых строк. Когда я вхожу в «сброс», все возвращается в норму, но, очевидно, я делаю что-то не так.

Есть ли способ получить такое же поведение, не испортив мою оболочку?

Спасибо!

Ответы [ 5 ]

14 голосов
/ 02 февраля 2011

Используя более простой пример

ls *.h | xargs vim

Вот несколько способов решить проблему:

xargs -a <( ls *.h ) vim

или

vim $( ls *.h | xargs )

или

ls *.h | xargs -o vim

В примере first используется флаг xargs -a (--arg-file), который сообщает xargs, что он берет данные из файла, а не из стандартного ввода. Файл, который мы передаем в этом случае, представляет собой замену процесса bash *, а не обычный файл.

Подстановка процесса берет вывод команды, содержащейся в <( ), помещает ее в файловый дескриптор и затем заменяет файловый дескриптор, в этом случае замещенная команда будет выглядеть примерно так: xargs -a /dev/fd/63 vim.

Команда second использует подстановку команд , команды выполняются в подоболочке и подставляются их данные stdout.

Команда третья использует флаг xargs --open-tty (-o), который страница руководства описывает следующим образом:

Снова открыть stdin как / dev / tty в дочернем процессе перед выполнением команда. Это полезно, если вы хотите, чтобы Xargs запускал интерактивный применение.

Если вы используете его по-старому и хотите, чтобы ваш терминал снова работал, вы можете использовать команду reset.

12 голосов
/ 04 октября 2010

Проблема в том, что поскольку вы запускаете xargs (и, следовательно, git и, следовательно, vim) в конвейере, его стандартный вывод берется из вывода cat projectPaths, а не из терминала; это сбивает с толку vim. К счастью, решение простое: добавьте флаг -o в xargs, и он запустит git (и, следовательно, vim) с вводом из / dev / tty вместо своего собственного стандартного ввода.

2 голосов
/ 04 октября 2010

Страница man для GNU xargs показывает аналогичную команду для emacs:

xargs sh -c 'emacs "$@" < /dev/tty' emacs

(в этой команде вторая "emacs" - это "фиктивная строка", на которую wisbucky ссылается в комментариина этот ответ)

и говорит следующее:

   Launches  the  minimum  number of copies of Emacs needed, one after the
   other, to edit the files listed on xargs' standard input.  This example
   achieves the same effect as BSD's -o option, but in a more flexible and
   portable way.

Еще одна попытка - использовать -a вместо cat:

xargs -a projectPaths -I project git --git-dir=project/.git --work-tree=project commit -a

или некоторая комбинация двух.

1 голос
/ 04 октября 2010

Если у вас установлен GNU Parallel http://www.gnu.org/software/parallel/, вы сможете сделать это:

cat projectPaths |
parallel -uj1 git --git-dir={}/.git --work-tree={} commit -a

В общем, это тоже работает:

cat filelist | parallel -Xuj1 $EDITOR

на случай, если вы хотите редактировать более одного файла за раз (и вы установили $ EDITOR для вашего любимого редактора).

-o для xargs (как уже упоминалось в другом месте) работает только для некоторых версий xargs (особенно это не работает для GNU xargs).

Посмотрите вступительное видео, чтобы узнать больше о GNU Parallel http://www.youtube.com/watch?v=OpaiGYxkSuQ

0 голосов
/ 04 октября 2010

Интересно!Я также вижу то же поведение на Mac, делая что-то простое:

ls * .h |xargs vim

Видимо, это проблема с vim:

http://talideon.com/weblog/2007/03/xargs-vim.cfm

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...