tl;dr
strace -o '|vim -' file.out
About -o
-o exists to provide additional output channel different than stdout or stderr. Without -o strace prints to its stderr which is also the stderr of the command (file.out in your case). It's good to be able to separate the two streams, -o makes this possible.
Problems
Your approach is flawed in a different way than you think, stty sane cannot help. Let me repeat the command:
strace -o >(vim -; stty sane) file.out; stty sane
There are two general problems with it:
- With job control enabled, there's a concept of foreground process group. At any time the terminal recognizes one group that is in the foreground. Processes not in the foreground process group are formally in the background.
A process in the background cannot read from its controlling terminal; it will receive SIGTTIN if it tries. The signal will stop it, unless the process ignores it or handles differently.
A process in the background can write to its controlling terminal, although if it tries and stty tostop is enabled then the process will receive SIGTTOU. The signal will stop it, unless the process ignores it or handles differently. If not stopped, the process is able to write to the terminal despite tostop and the signal.
The above mechanism prevents background processes from stealing input from the terminal, but still keeps them connected to it, so they can be brought to the foreground and then read from the terminal. This is useful for the terminal from which a process was started. Possible interaction with other terminals has nothing to do with being in the foreground or in the background, the other terminal is "foreign" anyway; therefore a process can read from or write to a terminal that is not its controlling terminal, if only it has sufficient permissions.
In your case initially the foreground process group is the one associated with the shell; then with strace; then with stty (the one outside >()); and finally with the shell again.
In Bash processes inside >() are assigned to the process group of the shell handling the >(). This means your vim is able to read from the terminal only after strace and stty (the one outside >()) finish and the shell's process group is put in the foreground. This brings the second problem.
- When
vim is finally able to read from the terminal, the shell also tries to read. Compare these two:
strace -o >(vim -) true
Move the cursor around. Some input will go to vim, some input will go to the shell. They are both in the foreground.
strace -o >(vim -) true; sleep 1000
Try to move the cursor around. Now it's different because sleep is in the foreground. Terminate sleep with Ctrl+C and the behavior will change.
In any case you can recover by killing vim from another console (killall vim, unless there is another vim and you want to keep it).
This is the madness you observed. The culprit is beyond the scope of stty sane, reset or tput reset.
Trivia
The following commands generate non-identical madness:
<<<"foo" tee >(vim -)
<<<"foo" tee > >(vim -)
In the first case >() is handled by the main shell and vim is placed in the process group of the shell. It will be able to read from the terminal as soon as tee exits (although the shell interferes); we've seen this before with strace.
In the second case >() is handled by the shell that handles >. It's a subshell that is going to become (exec to) tee. In effect vim is placed in a process group with tee. It is able to read from the terminal as long as tee stays in the foreground.
Because tee exits almost immediately, the first vim is almost immediately able to read from the terminal and the second vim is almost immediately unable to read.
- My tests indicate that
>(vim -) in Zsh places vim in yet another process group, not the one of the shell handling the >(). Then vim can never be in the foreground. It seems there are other differences but I won't elaborate.
General solutions (not depending on strace)
If you disable job control (with set +m or by running code in a subshell) then all new processes will belong to the group the terminal considers the foreground. If you delay your return to the shell, the shell won't interfere by reading from the terminal. Try this:
(strace -o >(vim -) file.out; sleep 99999)
Use Ctrl+C to terminate sleep after you exit vim. If you hit this combination in vim then sleep won't be affected because vim configures the terminal like stty -isig.
This solution is not really elegant. I'm including it here because it shows how things are affected by disabling job control and not allowing the shell to read input.
- Alternatively you need to start and keep
vim in the foreground. Do not use >(vim -). Use vim … or … | vim -.
The most straightforward way is to create a regular file (in your case strace -o somefile file.out) and to open it later (vim somefile).
Solution specific to strace
Solutions that avoid creating a file and use vim <(strace …) or strace … | vim - are possible. I guess if you are clever enough (and have /proc?) then you can manipulate file descriptors and pipe -o to stdout without merging with the original stdout.
The right thing however is to use what strace provides with -o:
-o filename
--output=filename
Write the trace output to the file filename rather than to stderr. […] If the argument begins with | or !, the rest of the argument is treated as a command and all output is piped to it. This is convenient for piping the debugging output to a program without affecting the redirections of executed programs. […]
(source, emphasis mine)
Your command becomes:
strace -o '|vim -' file.out
Note | must be quoted or escaped, otherwise the shell will try to build a pipeline. The alternative is !, in some shells it needs to be protected as well.
strace runs sh, sh runs vim. The problems stated above are solved. Respectively:
The three processes belong to the same process group. If strace is in the foreground, so is vim.
The interactive (outer) shell tries to read from the terminal only after strace exits after sh exits after vim exits.
stdin? The point is to only sets back the environment variable, becausevimsets them to null when input is not fromstdin(hence the strange behaviour inside vim), and therefor I am trying tostty sanebut to no avail – Herdsman May 23 '20 at 15:09teedoes not help :strace a.out | tee 1>/dev/null >(vim -)will not simply inputteein vim – Herdsman May 23 '20 at 15:28$ls -l <(echo abc)->lr-x------ 1 group user 64 May 23 20:49 /dev/fd/63 -> 'pipe:[33372]'. Though that is not solution to my question – Herdsman May 23 '20 at 18:52