Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Post History

66%
+2 −0
Q&A Capture separate _and_ combined stdout/stderr

Each file descriptor can only point to a single file. File descriptors can be duplicated such that both point to a single file, but a file descriptor cannot point to two files. Hence, you have ...

posted 2y ago by Quasímodo‭

Answer
#1: Initial revision by user avatar Quasímodo‭ · 2022-04-30T15:51:46Z (over 2 years ago)
Each [file descriptor](https://en.wikipedia.org/wiki/File_descriptor)
can only point to a single file. File descriptors can
be duplicated such that both point to a single file, but a file descriptor
cannot point to two files.

Hence, you have to decide whether stdout points to _out.txt_ or to _both.txt_,
and similarly with stderr.

Of course, you could use
[Tee](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/tee.html)
to replicate output, since it writes its input directly to files (given as
arguments) and to stdout, which you can further redirect.
One such approach, proposed in ["How to redirect
stderr and stdout to different files and also display in
terminal?"](https://unix.stackexchange.com/a/54974), is

    ((cmd | tee out.txt) 3>&1 1>&2 2>&3 | tee err.txt) &> both.txt

It, however, **fails** to preserve the order of
stdout and stderr output when writing to _both.txt_.

This is because once you send `cmd`'s stdout and stderr to different roads,
you can't guarantee that they will take the same time to traverse it. 

More technically: The two Tees are different, concurrent processes, and as
such incur in a
[race condition](https://en.wikipedia.org/wiki/Race_condition#In_software);
as a result the order of the lines in _both.txt_ is not deterministic.

Your proposed trick with Zsh `MULTIOS` also fails to address this issue,
since, [as documented](https://zsh.sourceforge.io/Doc/Release/Redirection.html),
it does essentially the same thing:

> the shell opens the file descriptor as a pipe to a process that copies
its input to all the specified outputs, similar to tee, provided the MULTIOS
option is set, as it is by default.

Unfortunately, although piping both stdout and stderr to another program
preserves the line order for _both.txt_, the program then couldn't tell them
apart in order to write _out.txt_ and _err.txt_. I.e., in

    cmd 2>&1 | filter

`filter` only has a notion of its stdin; the information of whether this or that
line "came from" `cmd`'s stdout or stderr is completely lost.

The only reliable and feasible solution I see is to edit the program's source
code so as to insert information in its output that shows which lines are
stdout and which are stderr (e.g. by prepending "E:" to stderr and "O:"
to stdout).  Too bad it is cumbersome and not scalable.