I have a shell script which writes all output to logfile and terminal, this part works fine, but if I execute the script a new shell prompt only appear if I press enter. Why is that and how do I fix it?
#!/bin/bash
exec > >(tee logfile)
echo "output"
First, when I'm testing this, there always is a new shell prompt, it's just that sometimes the string
output
comes after it, so the prompt isn't last. Did you happen to overlook it? If so, there seems to be a race where the shell prints the prompt before thetee
in the background completes.Unfortunately, that cannot fixed by
wait
ing in the shell fortee
, see this question on unix.stackexchange. Fragile workarounds aside, the easiest way to solve this that I see is to put your whole script inside a list:@chepner's answer provides great background information.
Here's a workaround - works on Ubuntu 12.04 (Linux 3.2.0) and on OS X 10.9.1:
Alternatives:
@user2719058's answer shows a simple alternative: wrapping the entire script body in a group command (
{ ... }
) and piping it totee logfile
.An external solution, as @chepner has already hinted at, is to use the
script
utility to create a "transcript" of your script's output in addition to displaying it:This, however, will also capture stderr output; if you wanted to avoid that, use:
Note, however, that this will suppress stderr output altogether.
If I run the following script (suppressing the newline from the
echo
), I see the prompt, but not "output". The string is still written to the file.What I suspect is this: you have three different file descriptors trying to write to the same file (that is, the terminal): standard output of the shell, standard error of the shell, and the standard output of
tee
. The shell writes synchronously: first theecho
to standard output, then the prompt to standard error, so the terminal is able to sequence them correctly. However, the third file descriptor is written to asynchronously bytee
, so there is a race condition. I don't quite understand how my modification affects the race, but it appears to upset some balance, allowing the prompt to be written at a different time and appear on the screen. (I expect output buffering to play a part in this).You might also try running your script after running the
script
command, which will log everything written to the terminal; if you wade through all the control characters in the file, you may notice the prompt in the file just prior to the output written bytee
. In support of my race condition theory, I'll note that after running the script a few times, it was no longer displaying "abnormal" behavior; my shell prompt was displayed as expected after the string "output", so there is definitely some non-deterministic element to this situation.As others have noted, it's not that there's no prompt printed -- it's that the last of the output written by
tee
can come after the prompt, making the prompt no longer visible.If you have bash 4.4 or newer, you can
wait
for yourtee
process to exit, like so: