Invoking vi through find | xargs breaks my terminal. Why?
Rise to the top 3% as a developer or hire one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------
Music by Eric Matyas
https://www.soundimage.org
Track title: Digital Sunset Looping
--
Chapters
00:00 Invoking Vi Through Find | Xargs Breaks My Terminal. Why?
00:29 Accepted Answer Score 117
01:53 Answer 2 Score 11
02:15 Answer 3 Score 186
03:03 Answer 4 Score 24
03:14 Thank you
--
Full question
https://superuser.com/questions/336016/i...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Tags
#vim #find
#avk47
ANSWER 1
Score 186
(Following on from grawity's explanation, that xargs
points stdin
to /dev/null
.)
The solution for this problem is to add the -o
parameter to xargs
.
From man xargs
:
-o
Reopen stdin as
/dev/tty
in the child process before executing the command. This is useful if you wantxargs
to run an interactive application.
Thus, the following line of code should work for you:
find . -name "*.txt" | xargs -o vim
GNU xargs supports this extension since some release in 2017
(with the long option name --open-tty
).
For older or other versions of xargs,
you 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.)
ACCEPTED ANSWER
Score 117
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<undef>
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.)
ANSWER 3
Score 24
It should work just fine if you use the -exec option on find rather than piping into xargs.
find . -type f -name filename.txt -exec vi {} +
ANSWER 4
Score 11
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