find | xargs, like this:
find . -name "*.txt" | xargs vim
you get a warning about
Input is not from a terminal
and a terminal with pretty much broken behaviour afterwards. Why is that?
When you invoke a program via
xargs, the program's stdin (standard input) points to
/dev/null. (Since xargs doesn't know the original stdin, it does the next best thing.)
$ true | xargs filan -s 0 chrdev /dev/null 1 tty /dev/pts/1 2 tty /dev/pts/1 $ true | xargs ls -l /dev/fd/
Vim expects its stdin to be the same as its controlling terminal, and performs various terminal-related ioctl's on stdin directly. When done on
/dev/null (or any non-tty file descriptor), those ioctls are meaningless and return ENOTTY, which gets silently ignored.
My guess at a more specific cause: On startup Vim reads and remembers the old terminal settings, and restores them back when exiting. In our situation, when the "old settings" are requested for a non-tty fd (file descriptor), Vim receives all values empty and all options disabled, and carelessly sets the same to your terminal.
You can see this by running
vim < /dev/null, exiting it, then running
stty, which will output a whole lot of
<undef>s. On Linux, running
stty sane will make the terminal usable again (although it will have lost such options as
iutf8, possibly causing minor annoyances later).
You could consider this a bug in Vim, since it can open
/dev/tty for terminal control, but doesn't. (At some point during startup, Vim duplicates its stderr to stdin, which allows it to read your input commands – from a fd opened for writing – but even that is not done early enough.)
Following on from grawity's answer,
-o 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.
Thus the following line of code should work for you:
find . -name "*.txt" | xargs -o vim
man xargs there is no flag, but we can explicitly pass in /dev/tty to solve the problem:
find . -name "*.txt" | xargs bash -c '</dev/tty vim "$@"' ignoreme
the ignoreme is there to take up $0, so that $@ is all arguments from xargs
Use GNU Parallel instead:
find . -name "*.txt" | parallel -j1 --tty vim
Or if you want to open all the files in one go:
find . -name "*.txt" | parallel -Xj1 --tty vim
It even deals correctly with filenames like:
My brother's 12" records.txt
Watch the intro video to learn more: http://www.youtube.com/watch?v=OpaiGYxkSuQ