Xargs с командой, что открытый редактор оставляет оболочку в странном состоянии

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

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

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

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

а потом мой терминал странный: он не отображает текст, который я печатаю, и, похоже, не выводит никаких строк перевода. Когда я вхожу в "reset", все в порядке, но я явно делаю что-то неправильно.

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

Спасибо!

Ответы

Ответ 1

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

Ответ 2

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

ls *.h | xargs vim

вы можете сделать это, чтобы исправить проблему:

vim $( ls *.h | xargs )

или

vim `ls *.h | xargs`

оба из этих примеров являются заменой команды. Второй пример с backticks устарел, поэтому вы должны использовать первый пример. Команды выполняются в подоболочке, и их данные stdout заменяются. Подробнее здесь.

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

Ответ 3

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

xargs sh -c 'emacs "[email protected]" < /dev/tty' emacs

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

   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 -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

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

Ответ 4

Если у вас установлен 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

Ответ 5

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

ls *.h | xargs vim

По-видимому, это проблема с vim:

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