2

I am looking for a bash command where I can redirect:

  1. stdout of a command to a file
  2. stderr to both that file and the console.

I have found ways where the stderr will append to the end of the file after the stdout, but I want it so that the output file orders all out the output chronologically like it would if I were to just use command &> file.

I have tried:

command 2>&1 1>logfile | tee -a logfile
command 2> >(tee -a logfile) 1>>logfile

I would basically like the output file to be same as if I simply did command &> logfile, whilst at the same time keep printing stderr messages to the console.

1
  • This stuff makes my head explode! I think you want a version of this: stackoverflow.com/a/44285135/6929343 which uses (cmd 2> >(tee /dev/stderr)) > log. The question and all the answers have a combined up-votes of 1000+ so there must be heads exploding all over the world :D Jun 12, 2018 at 23:40

4 Answers 4

2

Let's create a test function that sends some output to both stdout and stderr:

$ cmd() { echo 1 on stdout; echo 2 on stderr >&2; echo 3 on stdout; echo 4 on stderr >&2; }

Running it we see:

$ cmd
1 on stdout
2 on stderr
3 on stdout
4 on stderr

Now, we want to send the stdout to a file, and the stderr to both the file and the screen. For this we use a simple redirection for stdout, and for stderr we redirect into a process substitution that appends to the file and sends the output back to stderr:

$ cmd > cmd.out 2> >( tee -a cmd.out >&2 )
2 on stderr
4 on stderr

$ cat cmd.out
1 on stdout
3 on stdout
2 on stderr
4 on stderr

I do not know of a way to keep the chronological order of the intermixed stdout and stderr messages.

3
  • Thanks, but yeah that's the result I'm getting right now. I wish there was some way to keep them in chronological order, since you are able to do that if you are redirecting all of output only to the file by using &>...
    – erickque
    Jun 12, 2018 at 19:51
  • 1
    That regular, non-appending redirection (> cmd.out) is dangerous here. Depending on how the timing goes, the stdout output can overwrite the stderr output. Since cmd.out was opened twice, the file positions aren't locked together.
    – ilkkachu
    Jun 12, 2018 at 22:06
  • Great point. I was doing a test with some sleeps in between the echos, and the first stderr line got lost. This must be why. >cmd.out; cmd >> cmd.out 2> >(tee -a cmd.out >&2) would be the way to go. Jun 12, 2018 at 22:47
1

It works if you append stdout to the file and redirect stderr to tee, also appending to the file:

$ bash -c "echo a;bahs;echo b;bhas" >>file 2> >( tee -a file >&2 )
bash: bahs: command not found
bash: bhas: command not found
$ cat file
a
bash: bahs: command not found
b
bash: bhas: command not found

This doesn’t work with the test from glenn jackman’s answer and I can’t wrap my head around why.

1
  • That’s one of the worst answers I have ever written, but maybe someone can explain and teach me if this isn’t a solution to the problem.
    – dessert
    Jun 12, 2018 at 20:43
0

I don't think you can really do that.

When you redirect stdout and stderr separately, they become unsynchronized, and there's no way to fix them back again. What you're trying to do is something like this:

                  +------> terminal
                  |       
cmd -(stderr)--> tee ----> file
 |                          ^
 +---(stdout)---------------+      

Here, there are two parallel paths from cmd to file, with an additional process in the stderr path. Depending on the scheduling, there might be delays in the path that involves tee, which can and will lead to the stderr messages being delayed.

To prevent that, the system would need to switch to tee immediately when it gets input. Usually, it can't be counted on to do that. Adding another process to the parallel path won't help, as then the result will just depend on the scheduling between the two intermediate processes (instead of cmd and tee).

0

You can do something like this:

echo "asd" | xargs -I % sh -c 'echo % && echo % > asd'

First echo is passed to xargs which takes it as argument and build two echo's commands, first result is output to terminal and second to file named also asd as the text.

You can put the redirects after in order to match your needs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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