Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

xargs with command that open editor leaves shell in weird state

I tried to make an alias for committing several different git projects. I tried something like

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

where projectPaths is a file containing the paths to all the projects I want to commit. This seems to work for the most part, firing up vi in sequence for each project so that I can write a commit msg for it. I do, however, get a msg:

"Vim: Warning: Input is not from a terminal"

and afterward my terminal is weird: it doesn't show the text I type and doesn't seem to output any newlines. When I enter "reset" things pretty much back to normal, but clearly I'm doing something wrong.

Is there some way to get the same behavior without messing up my shell?

Thanks!

like image 836
initlaunch Avatar asked Oct 04 '10 03:10

initlaunch


2 Answers

Using the simpler example of

ls *.h | xargs vim

here are a few ways to fix the problem:

xargs -a <( ls *.h ) vim

or

vim $( ls *.h | xargs )

or

ls *.h | xargs -o vim

The first example uses the xargs -a (--arg-file) flag which tells xargs to take its input from a file rather than standard input. The file we give it in this case is a bash process substitution rather than a regular file.

Process substitution takes the output of the command contained in <( ) places it in a filedescriptor and then substitutes the filedescriptor, in this case the substituted command would be something like xargs -a /dev/fd/63 vim.

The second command uses command substitution, the commands are executed in a subshell, and their stdout data is substituted.

The third command uses the xargs --open-tty (-o) flag, which the man page describes thusly:

Reopen stdin as /dev/tty in the child process before executing the command. This is useful if you want xargs to run an interactive application.

If you do use it the old way and want to get your terminal to behave again you can use the reset command.

like image 196
htaccess Avatar answered Oct 23 '22 10:10

htaccess


The problem is that since you're running xargs (and hence git and hence vim) in a pipeline, its stdin is taken from the output of cat projectPaths rather than the terminal; this is confusing vim. Fortunately, the solution is simple: add the -o flag to xargs, and it'll start git (and hence vim) with input from /dev/tty, instead of its own stdin.

like image 22
Gordon Davisson Avatar answered Oct 23 '22 09:10

Gordon Davisson