Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I know how to redirect to a file, and use tee; on a basic level. So

$ alias outanderr='bash -c "echo stdout >&1; echo stderr >&2"'
# A fake "application" displaying both output and error messages.

$ outanderr 1>file      # redirect stdout to a file, display stderr
stderr

$ outanderr 2>file      # redirect stderr to a file, display stdout
stdout

$ outanderr 1>file 2>&1 # redirect both to a file, display nothing

$ outanderr | tee file; echo "-- file contents --" && cat file
# redirect stdout to a file, display both (note: order is messed up)
stderr
stdout
-- file contents --
stdout

$ outanderr 2>&1 | tee file; echo "-- file contents --" && cat file
# redirect both to a file, display both
stdout
stderr
-- file contents --
stdout
stderr

The question is: what to write in place of the questionmarks to get the output below:

$ outanderr ???; echo "-- file contents --" && cat file
# redirect both to a file, display stderr
stderr
-- file contents --
stdout
stderr

Constaints:

  • Assuming bash.
  • The order should be kept in the file.
  • stderr contents are displayed in real time line by line, i.e. no buffering.
  • Separate script files can be used.
  • Magic may be necessary.
share|improve this question
    
How much control of the outanderr program do you have? –  Kevin Jun 19 '13 at 15:02
1  
@Kevin I think the question is more generic than that. Here, outanderr is just an alias that prints a line to stdout and another to stderr. The idea (if it's possible) is to build a generic solution that could work with any program, without modifying them. –  lgeorget Jun 19 '13 at 15:06
    
@lgeorget I understand that, but I don't believe it is possible to strictly meet all constraints in a generic solution, so I was seeing if we could get a specific one. –  Kevin Jun 19 '13 at 15:10
    
@Igeorget is right. –  TWiStErRob Jun 20 '13 at 17:51

1 Answer 1

up vote 7 down vote accepted
2>&1 >>outputfile | tee --append outputfile

For easy testing:

echo -n >outputfile; bash -c "echo stdout >&1; echo stderr >&2" 2>&1 >>outputfile |
  tee --append outputfile; echo "outputfile:"; cat outputfile

Edit 1:

This works by writing stdout (only) to the file, making sterr stdout so that it goes through the pipe, and having tee write its output to the same file.

Both writes must be done in append mode (>> instead of >) otherwise both would overwrite each others output.

As the pipe is a buffer there is no guarantee that the output appears in the file in the right order. This would not even change if an application was connected to both file descriptors (two pipes). For guaranteed order both outputs would have to go through the same channel and be marked respectively. Or you would need some really fancy stuff:

  1. If both stdout and stderr were redirected to a file (not the same file!) and both files were on a FUSE volume then the FUSE module could mark each single write with a timestamp so that a second application could sort the data correctly and combine it for the real output file. Or you don't mark the data but have the module create the combined output file. Most probably there is no FUSE module yet which does this...
  2. Both stdout and stderr could be directed to /dev/null. The outputs of the application would be separated by running it through strace -f -s 32000 -e trace=write. You would have to reverse the escaping in that case. Needless to say that the application does not run faster by being traced.
  3. Maybe the same could be reached by using an existing, simple FUSE module and tracing the module instead of the application. This may be faster than tracing the application because (or rather: if) the module probably has a lot less syscalls than the application.
  4. If the application itself can be modified: The app could be stopped after each output (but I think this is possible from the inside only) and continue only after receiving s signal (SIGUSR1 or SIGCONT). The application reading from the pipe would have to check both the pipe and the file for new data and to send the signal after each new data. Depending on the kind of application this may be faster or even slower than the strace method. FUSE would be the maximum speed solution.
share|improve this answer
    
Bah. Catch me in the middle of writing up precisely the same answer why don't'cha. –  Kevin Jun 19 '13 at 15:20
1  
N.B. this has a race condition introducing the possibility of swapping out/err lines, but I don't think that can be avoided. –  Kevin Jun 19 '13 at 15:21
1  
@Kevin That happens to the best of us, I've suffered from it before and had nearly asked for a "show me that somebody is writing" feature (which would be complicated, though). It seems to me that the race condition occurs only if a write to the file (stdout) occurs after a write to the pipeline. –  Hauke Laging Jun 19 '13 at 15:26
    
Wouldn't that send both stdout and stderr to tee, or am I missing something? I think the OP's requirement is to tee stderr only. –  Joseph R. Jun 19 '13 at 17:05
    
@JosephR. You don't happen to have given that a try? –  Hauke Laging Jun 19 '13 at 21:21

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.