When invoking vim
through 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?
Answer
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 runningstty
, which will output a whole lot of
s. On Linux, runningstty sane
will make the terminal usable again (although it will have lost such options asiutf8
, 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.)
Comments
Post a Comment