How to redirect stdout to a file, and stdout+stderr to another one?Show only stderr on screen but write both stdout and stderr to fileAppend output to a file and redirect stderr to nullRedirect stderr and stdout to another file descriptorRedirect script stderr & stdout to a file, but keep stdout to tty as well?bash: redirect stderr to file and stdout + stderr to screenRedirect bash stdout+stderr to one file and stderr to another fileAppend stderr and stdout to filestdout and stderr redirection to different files
Does immunity to fear prevent a mummy's Dreadful Glare from paralyzing a character?
Word for 'most late'
How does a ball bearing door hinge work?
Which culture used no personal names?
What's that funny "illo" I keep hearing in Southern Spain?
Encountering former, abusive advisor at a conference
How does an alien race from a dying world annihilate most of humanity to colonize the planet for themselves?
If we should encrypt the message rather than the method of transfer, why do we care about wifi security? Is this just security theatre?
What's the meaning of java.util.@Nullable?
Did Terry Pratchett ever explain the inspiration behind the Luggage?
Christmas party at employers home
Is is possible to externally power my DSLR with the original battery that is connected to the DSLR by means of wires?
How to figure out key from key signature?
How can you tell apart the pronounciation at the end between the "meine" and "meiner" in the daily spoken situation?
Does my protagonist need to be the most important character?
Do more Americans want the Bidens investigated than Trump impeached?
Where is the circle of fifths mentioned for the first time?
Company indirectly discriminating against introverts, specifically INTJ
Does a quantum computer have a clock signal and if yes how big is it?
How to increment the value of a (decimal) variable (with leading zero) by +1?
Moonlight bright enough to see by
Code Golf Measurer © 2019
How (and if) to include name change for transgender person in genealogy?
Get injured / Get increased
How to redirect stdout to a file, and stdout+stderr to another one?
Show only stderr on screen but write both stdout and stderr to fileAppend output to a file and redirect stderr to nullRedirect stderr and stdout to another file descriptorRedirect script stderr & stdout to a file, but keep stdout to tty as well?bash: redirect stderr to file and stdout + stderr to screenRedirect bash stdout+stderr to one file and stderr to another fileAppend stderr and stdout to filestdout and stderr redirection to different files
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;
How can I achieve
cmd >> file1 2>&1 1>>file2
That is, the stdout and stderr should redirect to one file (file1) and only stdout (file2) should redirect to another (both in append mode)?
shell io-redirection io stdout stderr
add a comment
|
How can I achieve
cmd >> file1 2>&1 1>>file2
That is, the stdout and stderr should redirect to one file (file1) and only stdout (file2) should redirect to another (both in append mode)?
shell io-redirection io stdout stderr
add a comment
|
How can I achieve
cmd >> file1 2>&1 1>>file2
That is, the stdout and stderr should redirect to one file (file1) and only stdout (file2) should redirect to another (both in append mode)?
shell io-redirection io stdout stderr
How can I achieve
cmd >> file1 2>&1 1>>file2
That is, the stdout and stderr should redirect to one file (file1) and only stdout (file2) should redirect to another (both in append mode)?
shell io-redirection io stdout stderr
shell io-redirection io stdout stderr
edited May 15 at 5:23
Scott
7,6525 gold badges30 silver badges54 bronze badges
7,6525 gold badges30 silver badges54 bronze badges
asked May 13 at 10:38
Swarna GowriSwarna Gowri
3052 silver badges7 bronze badges
3052 silver badges7 bronze badges
add a comment
|
add a comment
|
5 Answers
5
active
oldest
votes
Problem is that when you redirect your output, it's not available anymore for the next redirect. You can pipe to tee
in a subshell to keep the output for the second redirection:
( cmd | tee -a file2 ) >> file1 2>&1
or if you like to see the output in terminal:
( cmd | tee -a file2 ) 2>&1 | tee -a file1
To avoid adding the stderr of the first tee
to file1
, you should redirect the stderr of your command to some file descriptor (e.g. 3), and later add this to stdout again:
( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1
(thanks @fra-san)
add a comment
|
With zsh
:
cmd >& out+err.log > out.log
In append mode:
cmd >>& out+err.log >> out.log
In zsh
, and provided the mult_ios
option has not been disabled, when a file descriptor (here 1) is redirected several times for writing, then the shell implements a built-in tee
to duplicate the output to all targets.
I can't figure out whatout+err
andout
mean here. File names? Streams to be redirected?
– gronostaj
May 13 at 20:27
@gronostaj Think that the command readscmd >& file1 > file2
– Isaac
May 13 at 22:00
This solution will preserve the order in which the output was generated. To actually store the stdout and stderr (in that order) you need a different approach.
– Isaac
May 13 at 22:02
1
@Isaac, the order will not necessarily be preserved as the stdout output will go through a pipe (to a process that forwards it to each file) while the stderr output will go directly to the file. In any case, it doesn't look like the OP asked for the stderr output to come after the stdout one.
– Stéphane Chazelas
May 14 at 11:07
add a comment
|
You could : tag stdout (using an UNBUFFERED sed, ie: sed -u ...
), have stderr also go to stdout (untagged, as it didn't go through that tagging sed), and thus be able to differentiate the 2 in the resulting logfile.
The following: is slow (It can be seriously optimized, by using for exemple a perl script instead of the while ... ; do ... ;done, for exemple, that will spawning subshells & commands at every lines!), weird (it seems I need the 2 stages to in one rename stdout and then in the other one add the "falled through" stderr to it), etc. But it is : a "proof of concept", that will try to keep the output's order the most of stdout & stderr as much as possible:
#basic principle (some un-necessary "" to visually help see the layers):
# sed -e "s/^/TAGstdout/" ; 2>&1 | read_stdin_and_redispatch
#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
# to see if the order of stdout&stderr is kept
#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
rm out.file out_AND_err.file unknown unknown2
touch existing existing2 existing3
#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs...
# avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.
sed -u -e "s/^/$uniquetag/" ;
2>&1 | while IFS="" read -r line ; do
case "$line" in
$uniquetag*) printf "%sn" "$line" | tee -a out_AND_err.file | sed -e "s/^$uniquetag//" >> out.file ;;
*) printf "%sn" "$line" >> out_AND_err.file ;;
esac;
done;
# see the results:
grep "^" out.file out_AND_err.file
This is really difficult to understand. (1) Why do you use such complicated use case (ls unknown
) to print something on stderr?>&2 echo "error"
would be fine. (2)tee
can append to multiple files at once. (3) Why not justcat
instead ofgrep "^"
? (4) your script will fail when stderr output begins with_stdout_
. (5) Why?
– pLumo
May 13 at 13:39
@RoVo : the first 2 commented lines shows the algorithm, simpler than the proof of concept example. 1) : thisls loop
will both output on stdout and stderr, mixed (alternatively), in a controlled order,;so that we can check we kept that stderr/stdout ordering despite the tagging of stdout 2) : gnu tail, maybe, but not regular tail (ex, on aix.). 3) : grep "^" also shows both filenames. 4) : this can be changed by the variable. 5) : the convoluted exemple works on old oses (ex, old aix) where I tested it (no perl available).
– Olivier Dulac
May 13 at 13:48
(1) multiple echo to stderr and stout would be fine, but okay, not important, would just be easier to read. (3) agree, (4) sure, but it will fail if it starts with whatever the variable contains. (5) I see.
– pLumo
May 13 at 13:51
@RoVo I agree with your 1). for 4), the variable could be as complex as needed to make the pb disappear (ex:uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
... )
– Olivier Dulac
May 13 at 13:54
1
Sure sure, it's not very likely, but anyways it might introduce a security issue later on. And then you might want to remove that string before printing to file ;-)
– pLumo
May 13 at 13:55
|
show 1 more comment
If order of output must be: stdout then stderr; there is no solution with redirection only.
The stderr must be stored to a temporal file
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
Description:
The only way to redirect one output (an fd like stdout or stderr) to two files is to reproduce it. The command tee
is the correct tool to reproduce a file descriptor content. So, an initial idea to have one output on two files would be to use:
... | tee file1 file2
That reproduces the stdin of tee to both files (1 & 2) leaving the output of tee still unused. But we need to append (use -a
) and only need one copy. This solve both issues:
... | tee -a file1 >>file2
To supply tee
with stdout (the one to repeat) we need to consume stderr directly out of the command. One way, if order is not important (order of output will (most probably) be preserved as generated, whichever is output first will be stored first). Either:
cmd 2>>file1 | tee -a file2 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
Option 2 works only in some shells. Option 3 uses an additional subshell (slower) but use the file names only once.
But if stdout must be first (whichever order output is generated) we need to store stderr to append it to file at the end (first solution posted).
1
Or store in memory likesponge
does:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
– Stéphane Chazelas
May 14 at 11:15
add a comment
|
In the interests of diversity:
If your system supports /dev/stderr
, then
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
will work.
The standard output of the cmd
is sent to both the stdout and the stderr of the pipeline.
The standard error of the cmd
bypasses the tee
and comes out the stderr of the pipeline.
So
- the stdout of the pipeline is just the stdout of the
cmd
, and - the stderr of the pipeline is the stdout and stderr of the
cmd
,
intermixed.
It's then a simple matter of sending those streams to the correct files.
As with almost any approach like this (including Stéphane’s answer),file1
may get lines out of order.
add a comment
|
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f518655%2fhow-to-redirect-stdout-to-a-file-and-stdoutstderr-to-another-one%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
Problem is that when you redirect your output, it's not available anymore for the next redirect. You can pipe to tee
in a subshell to keep the output for the second redirection:
( cmd | tee -a file2 ) >> file1 2>&1
or if you like to see the output in terminal:
( cmd | tee -a file2 ) 2>&1 | tee -a file1
To avoid adding the stderr of the first tee
to file1
, you should redirect the stderr of your command to some file descriptor (e.g. 3), and later add this to stdout again:
( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1
(thanks @fra-san)
add a comment
|
Problem is that when you redirect your output, it's not available anymore for the next redirect. You can pipe to tee
in a subshell to keep the output for the second redirection:
( cmd | tee -a file2 ) >> file1 2>&1
or if you like to see the output in terminal:
( cmd | tee -a file2 ) 2>&1 | tee -a file1
To avoid adding the stderr of the first tee
to file1
, you should redirect the stderr of your command to some file descriptor (e.g. 3), and later add this to stdout again:
( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1
(thanks @fra-san)
add a comment
|
Problem is that when you redirect your output, it's not available anymore for the next redirect. You can pipe to tee
in a subshell to keep the output for the second redirection:
( cmd | tee -a file2 ) >> file1 2>&1
or if you like to see the output in terminal:
( cmd | tee -a file2 ) 2>&1 | tee -a file1
To avoid adding the stderr of the first tee
to file1
, you should redirect the stderr of your command to some file descriptor (e.g. 3), and later add this to stdout again:
( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1
(thanks @fra-san)
Problem is that when you redirect your output, it's not available anymore for the next redirect. You can pipe to tee
in a subshell to keep the output for the second redirection:
( cmd | tee -a file2 ) >> file1 2>&1
or if you like to see the output in terminal:
( cmd | tee -a file2 ) 2>&1 | tee -a file1
To avoid adding the stderr of the first tee
to file1
, you should redirect the stderr of your command to some file descriptor (e.g. 3), and later add this to stdout again:
( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1
(thanks @fra-san)
edited May 13 at 14:20
answered May 13 at 11:20
pLumopLumo
7,93115 silver badges36 bronze badges
7,93115 silver badges36 bronze badges
add a comment
|
add a comment
|
With zsh
:
cmd >& out+err.log > out.log
In append mode:
cmd >>& out+err.log >> out.log
In zsh
, and provided the mult_ios
option has not been disabled, when a file descriptor (here 1) is redirected several times for writing, then the shell implements a built-in tee
to duplicate the output to all targets.
I can't figure out whatout+err
andout
mean here. File names? Streams to be redirected?
– gronostaj
May 13 at 20:27
@gronostaj Think that the command readscmd >& file1 > file2
– Isaac
May 13 at 22:00
This solution will preserve the order in which the output was generated. To actually store the stdout and stderr (in that order) you need a different approach.
– Isaac
May 13 at 22:02
1
@Isaac, the order will not necessarily be preserved as the stdout output will go through a pipe (to a process that forwards it to each file) while the stderr output will go directly to the file. In any case, it doesn't look like the OP asked for the stderr output to come after the stdout one.
– Stéphane Chazelas
May 14 at 11:07
add a comment
|
With zsh
:
cmd >& out+err.log > out.log
In append mode:
cmd >>& out+err.log >> out.log
In zsh
, and provided the mult_ios
option has not been disabled, when a file descriptor (here 1) is redirected several times for writing, then the shell implements a built-in tee
to duplicate the output to all targets.
I can't figure out whatout+err
andout
mean here. File names? Streams to be redirected?
– gronostaj
May 13 at 20:27
@gronostaj Think that the command readscmd >& file1 > file2
– Isaac
May 13 at 22:00
This solution will preserve the order in which the output was generated. To actually store the stdout and stderr (in that order) you need a different approach.
– Isaac
May 13 at 22:02
1
@Isaac, the order will not necessarily be preserved as the stdout output will go through a pipe (to a process that forwards it to each file) while the stderr output will go directly to the file. In any case, it doesn't look like the OP asked for the stderr output to come after the stdout one.
– Stéphane Chazelas
May 14 at 11:07
add a comment
|
With zsh
:
cmd >& out+err.log > out.log
In append mode:
cmd >>& out+err.log >> out.log
In zsh
, and provided the mult_ios
option has not been disabled, when a file descriptor (here 1) is redirected several times for writing, then the shell implements a built-in tee
to duplicate the output to all targets.
With zsh
:
cmd >& out+err.log > out.log
In append mode:
cmd >>& out+err.log >> out.log
In zsh
, and provided the mult_ios
option has not been disabled, when a file descriptor (here 1) is redirected several times for writing, then the shell implements a built-in tee
to duplicate the output to all targets.
edited May 14 at 11:08
answered May 13 at 14:50
Stéphane ChazelasStéphane Chazelas
337k58 gold badges661 silver badges1038 bronze badges
337k58 gold badges661 silver badges1038 bronze badges
I can't figure out whatout+err
andout
mean here. File names? Streams to be redirected?
– gronostaj
May 13 at 20:27
@gronostaj Think that the command readscmd >& file1 > file2
– Isaac
May 13 at 22:00
This solution will preserve the order in which the output was generated. To actually store the stdout and stderr (in that order) you need a different approach.
– Isaac
May 13 at 22:02
1
@Isaac, the order will not necessarily be preserved as the stdout output will go through a pipe (to a process that forwards it to each file) while the stderr output will go directly to the file. In any case, it doesn't look like the OP asked for the stderr output to come after the stdout one.
– Stéphane Chazelas
May 14 at 11:07
add a comment
|
I can't figure out whatout+err
andout
mean here. File names? Streams to be redirected?
– gronostaj
May 13 at 20:27
@gronostaj Think that the command readscmd >& file1 > file2
– Isaac
May 13 at 22:00
This solution will preserve the order in which the output was generated. To actually store the stdout and stderr (in that order) you need a different approach.
– Isaac
May 13 at 22:02
1
@Isaac, the order will not necessarily be preserved as the stdout output will go through a pipe (to a process that forwards it to each file) while the stderr output will go directly to the file. In any case, it doesn't look like the OP asked for the stderr output to come after the stdout one.
– Stéphane Chazelas
May 14 at 11:07
I can't figure out what
out+err
and out
mean here. File names? Streams to be redirected?– gronostaj
May 13 at 20:27
I can't figure out what
out+err
and out
mean here. File names? Streams to be redirected?– gronostaj
May 13 at 20:27
@gronostaj Think that the command reads
cmd >& file1 > file2
– Isaac
May 13 at 22:00
@gronostaj Think that the command reads
cmd >& file1 > file2
– Isaac
May 13 at 22:00
This solution will preserve the order in which the output was generated. To actually store the stdout and stderr (in that order) you need a different approach.
– Isaac
May 13 at 22:02
This solution will preserve the order in which the output was generated. To actually store the stdout and stderr (in that order) you need a different approach.
– Isaac
May 13 at 22:02
1
1
@Isaac, the order will not necessarily be preserved as the stdout output will go through a pipe (to a process that forwards it to each file) while the stderr output will go directly to the file. In any case, it doesn't look like the OP asked for the stderr output to come after the stdout one.
– Stéphane Chazelas
May 14 at 11:07
@Isaac, the order will not necessarily be preserved as the stdout output will go through a pipe (to a process that forwards it to each file) while the stderr output will go directly to the file. In any case, it doesn't look like the OP asked for the stderr output to come after the stdout one.
– Stéphane Chazelas
May 14 at 11:07
add a comment
|
You could : tag stdout (using an UNBUFFERED sed, ie: sed -u ...
), have stderr also go to stdout (untagged, as it didn't go through that tagging sed), and thus be able to differentiate the 2 in the resulting logfile.
The following: is slow (It can be seriously optimized, by using for exemple a perl script instead of the while ... ; do ... ;done, for exemple, that will spawning subshells & commands at every lines!), weird (it seems I need the 2 stages to in one rename stdout and then in the other one add the "falled through" stderr to it), etc. But it is : a "proof of concept", that will try to keep the output's order the most of stdout & stderr as much as possible:
#basic principle (some un-necessary "" to visually help see the layers):
# sed -e "s/^/TAGstdout/" ; 2>&1 | read_stdin_and_redispatch
#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
# to see if the order of stdout&stderr is kept
#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
rm out.file out_AND_err.file unknown unknown2
touch existing existing2 existing3
#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs...
# avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.
sed -u -e "s/^/$uniquetag/" ;
2>&1 | while IFS="" read -r line ; do
case "$line" in
$uniquetag*) printf "%sn" "$line" | tee -a out_AND_err.file | sed -e "s/^$uniquetag//" >> out.file ;;
*) printf "%sn" "$line" >> out_AND_err.file ;;
esac;
done;
# see the results:
grep "^" out.file out_AND_err.file
This is really difficult to understand. (1) Why do you use such complicated use case (ls unknown
) to print something on stderr?>&2 echo "error"
would be fine. (2)tee
can append to multiple files at once. (3) Why not justcat
instead ofgrep "^"
? (4) your script will fail when stderr output begins with_stdout_
. (5) Why?
– pLumo
May 13 at 13:39
@RoVo : the first 2 commented lines shows the algorithm, simpler than the proof of concept example. 1) : thisls loop
will both output on stdout and stderr, mixed (alternatively), in a controlled order,;so that we can check we kept that stderr/stdout ordering despite the tagging of stdout 2) : gnu tail, maybe, but not regular tail (ex, on aix.). 3) : grep "^" also shows both filenames. 4) : this can be changed by the variable. 5) : the convoluted exemple works on old oses (ex, old aix) where I tested it (no perl available).
– Olivier Dulac
May 13 at 13:48
(1) multiple echo to stderr and stout would be fine, but okay, not important, would just be easier to read. (3) agree, (4) sure, but it will fail if it starts with whatever the variable contains. (5) I see.
– pLumo
May 13 at 13:51
@RoVo I agree with your 1). for 4), the variable could be as complex as needed to make the pb disappear (ex:uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
... )
– Olivier Dulac
May 13 at 13:54
1
Sure sure, it's not very likely, but anyways it might introduce a security issue later on. And then you might want to remove that string before printing to file ;-)
– pLumo
May 13 at 13:55
|
show 1 more comment
You could : tag stdout (using an UNBUFFERED sed, ie: sed -u ...
), have stderr also go to stdout (untagged, as it didn't go through that tagging sed), and thus be able to differentiate the 2 in the resulting logfile.
The following: is slow (It can be seriously optimized, by using for exemple a perl script instead of the while ... ; do ... ;done, for exemple, that will spawning subshells & commands at every lines!), weird (it seems I need the 2 stages to in one rename stdout and then in the other one add the "falled through" stderr to it), etc. But it is : a "proof of concept", that will try to keep the output's order the most of stdout & stderr as much as possible:
#basic principle (some un-necessary "" to visually help see the layers):
# sed -e "s/^/TAGstdout/" ; 2>&1 | read_stdin_and_redispatch
#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
# to see if the order of stdout&stderr is kept
#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
rm out.file out_AND_err.file unknown unknown2
touch existing existing2 existing3
#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs...
# avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.
sed -u -e "s/^/$uniquetag/" ;
2>&1 | while IFS="" read -r line ; do
case "$line" in
$uniquetag*) printf "%sn" "$line" | tee -a out_AND_err.file | sed -e "s/^$uniquetag//" >> out.file ;;
*) printf "%sn" "$line" >> out_AND_err.file ;;
esac;
done;
# see the results:
grep "^" out.file out_AND_err.file
This is really difficult to understand. (1) Why do you use such complicated use case (ls unknown
) to print something on stderr?>&2 echo "error"
would be fine. (2)tee
can append to multiple files at once. (3) Why not justcat
instead ofgrep "^"
? (4) your script will fail when stderr output begins with_stdout_
. (5) Why?
– pLumo
May 13 at 13:39
@RoVo : the first 2 commented lines shows the algorithm, simpler than the proof of concept example. 1) : thisls loop
will both output on stdout and stderr, mixed (alternatively), in a controlled order,;so that we can check we kept that stderr/stdout ordering despite the tagging of stdout 2) : gnu tail, maybe, but not regular tail (ex, on aix.). 3) : grep "^" also shows both filenames. 4) : this can be changed by the variable. 5) : the convoluted exemple works on old oses (ex, old aix) where I tested it (no perl available).
– Olivier Dulac
May 13 at 13:48
(1) multiple echo to stderr and stout would be fine, but okay, not important, would just be easier to read. (3) agree, (4) sure, but it will fail if it starts with whatever the variable contains. (5) I see.
– pLumo
May 13 at 13:51
@RoVo I agree with your 1). for 4), the variable could be as complex as needed to make the pb disappear (ex:uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
... )
– Olivier Dulac
May 13 at 13:54
1
Sure sure, it's not very likely, but anyways it might introduce a security issue later on. And then you might want to remove that string before printing to file ;-)
– pLumo
May 13 at 13:55
|
show 1 more comment
You could : tag stdout (using an UNBUFFERED sed, ie: sed -u ...
), have stderr also go to stdout (untagged, as it didn't go through that tagging sed), and thus be able to differentiate the 2 in the resulting logfile.
The following: is slow (It can be seriously optimized, by using for exemple a perl script instead of the while ... ; do ... ;done, for exemple, that will spawning subshells & commands at every lines!), weird (it seems I need the 2 stages to in one rename stdout and then in the other one add the "falled through" stderr to it), etc. But it is : a "proof of concept", that will try to keep the output's order the most of stdout & stderr as much as possible:
#basic principle (some un-necessary "" to visually help see the layers):
# sed -e "s/^/TAGstdout/" ; 2>&1 | read_stdin_and_redispatch
#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
# to see if the order of stdout&stderr is kept
#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
rm out.file out_AND_err.file unknown unknown2
touch existing existing2 existing3
#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs...
# avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.
sed -u -e "s/^/$uniquetag/" ;
2>&1 | while IFS="" read -r line ; do
case "$line" in
$uniquetag*) printf "%sn" "$line" | tee -a out_AND_err.file | sed -e "s/^$uniquetag//" >> out.file ;;
*) printf "%sn" "$line" >> out_AND_err.file ;;
esac;
done;
# see the results:
grep "^" out.file out_AND_err.file
You could : tag stdout (using an UNBUFFERED sed, ie: sed -u ...
), have stderr also go to stdout (untagged, as it didn't go through that tagging sed), and thus be able to differentiate the 2 in the resulting logfile.
The following: is slow (It can be seriously optimized, by using for exemple a perl script instead of the while ... ; do ... ;done, for exemple, that will spawning subshells & commands at every lines!), weird (it seems I need the 2 stages to in one rename stdout and then in the other one add the "falled through" stderr to it), etc. But it is : a "proof of concept", that will try to keep the output's order the most of stdout & stderr as much as possible:
#basic principle (some un-necessary "" to visually help see the layers):
# sed -e "s/^/TAGstdout/" ; 2>&1 | read_stdin_and_redispatch
#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
# to see if the order of stdout&stderr is kept
#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
rm out.file out_AND_err.file unknown unknown2
touch existing existing2 existing3
#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs...
# avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.
sed -u -e "s/^/$uniquetag/" ;
2>&1 | while IFS="" read -r line ; do
case "$line" in
$uniquetag*) printf "%sn" "$line" | tee -a out_AND_err.file | sed -e "s/^$uniquetag//" >> out.file ;;
*) printf "%sn" "$line" >> out_AND_err.file ;;
esac;
done;
# see the results:
grep "^" out.file out_AND_err.file
edited May 13 at 13:57
answered May 13 at 13:23
Olivier DulacOlivier Dulac
3,99313 silver badges25 bronze badges
3,99313 silver badges25 bronze badges
This is really difficult to understand. (1) Why do you use such complicated use case (ls unknown
) to print something on stderr?>&2 echo "error"
would be fine. (2)tee
can append to multiple files at once. (3) Why not justcat
instead ofgrep "^"
? (4) your script will fail when stderr output begins with_stdout_
. (5) Why?
– pLumo
May 13 at 13:39
@RoVo : the first 2 commented lines shows the algorithm, simpler than the proof of concept example. 1) : thisls loop
will both output on stdout and stderr, mixed (alternatively), in a controlled order,;so that we can check we kept that stderr/stdout ordering despite the tagging of stdout 2) : gnu tail, maybe, but not regular tail (ex, on aix.). 3) : grep "^" also shows both filenames. 4) : this can be changed by the variable. 5) : the convoluted exemple works on old oses (ex, old aix) where I tested it (no perl available).
– Olivier Dulac
May 13 at 13:48
(1) multiple echo to stderr and stout would be fine, but okay, not important, would just be easier to read. (3) agree, (4) sure, but it will fail if it starts with whatever the variable contains. (5) I see.
– pLumo
May 13 at 13:51
@RoVo I agree with your 1). for 4), the variable could be as complex as needed to make the pb disappear (ex:uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
... )
– Olivier Dulac
May 13 at 13:54
1
Sure sure, it's not very likely, but anyways it might introduce a security issue later on. And then you might want to remove that string before printing to file ;-)
– pLumo
May 13 at 13:55
|
show 1 more comment
This is really difficult to understand. (1) Why do you use such complicated use case (ls unknown
) to print something on stderr?>&2 echo "error"
would be fine. (2)tee
can append to multiple files at once. (3) Why not justcat
instead ofgrep "^"
? (4) your script will fail when stderr output begins with_stdout_
. (5) Why?
– pLumo
May 13 at 13:39
@RoVo : the first 2 commented lines shows the algorithm, simpler than the proof of concept example. 1) : thisls loop
will both output on stdout and stderr, mixed (alternatively), in a controlled order,;so that we can check we kept that stderr/stdout ordering despite the tagging of stdout 2) : gnu tail, maybe, but not regular tail (ex, on aix.). 3) : grep "^" also shows both filenames. 4) : this can be changed by the variable. 5) : the convoluted exemple works on old oses (ex, old aix) where I tested it (no perl available).
– Olivier Dulac
May 13 at 13:48
(1) multiple echo to stderr and stout would be fine, but okay, not important, would just be easier to read. (3) agree, (4) sure, but it will fail if it starts with whatever the variable contains. (5) I see.
– pLumo
May 13 at 13:51
@RoVo I agree with your 1). for 4), the variable could be as complex as needed to make the pb disappear (ex:uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
... )
– Olivier Dulac
May 13 at 13:54
1
Sure sure, it's not very likely, but anyways it might introduce a security issue later on. And then you might want to remove that string before printing to file ;-)
– pLumo
May 13 at 13:55
This is really difficult to understand. (1) Why do you use such complicated use case (
ls unknown
) to print something on stderr? >&2 echo "error"
would be fine. (2) tee
can append to multiple files at once. (3) Why not just cat
instead of grep "^"
? (4) your script will fail when stderr output begins with _stdout_
. (5) Why?– pLumo
May 13 at 13:39
This is really difficult to understand. (1) Why do you use such complicated use case (
ls unknown
) to print something on stderr? >&2 echo "error"
would be fine. (2) tee
can append to multiple files at once. (3) Why not just cat
instead of grep "^"
? (4) your script will fail when stderr output begins with _stdout_
. (5) Why?– pLumo
May 13 at 13:39
@RoVo : the first 2 commented lines shows the algorithm, simpler than the proof of concept example. 1) : this
ls loop
will both output on stdout and stderr, mixed (alternatively), in a controlled order,;so that we can check we kept that stderr/stdout ordering despite the tagging of stdout 2) : gnu tail, maybe, but not regular tail (ex, on aix.). 3) : grep "^" also shows both filenames. 4) : this can be changed by the variable. 5) : the convoluted exemple works on old oses (ex, old aix) where I tested it (no perl available).– Olivier Dulac
May 13 at 13:48
@RoVo : the first 2 commented lines shows the algorithm, simpler than the proof of concept example. 1) : this
ls loop
will both output on stdout and stderr, mixed (alternatively), in a controlled order,;so that we can check we kept that stderr/stdout ordering despite the tagging of stdout 2) : gnu tail, maybe, but not regular tail (ex, on aix.). 3) : grep "^" also shows both filenames. 4) : this can be changed by the variable. 5) : the convoluted exemple works on old oses (ex, old aix) where I tested it (no perl available).– Olivier Dulac
May 13 at 13:48
(1) multiple echo to stderr and stout would be fine, but okay, not important, would just be easier to read. (3) agree, (4) sure, but it will fail if it starts with whatever the variable contains. (5) I see.
– pLumo
May 13 at 13:51
(1) multiple echo to stderr and stout would be fine, but okay, not important, would just be easier to read. (3) agree, (4) sure, but it will fail if it starts with whatever the variable contains. (5) I see.
– pLumo
May 13 at 13:51
@RoVo I agree with your 1). for 4), the variable could be as complex as needed to make the pb disappear (ex:
uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
... )– Olivier Dulac
May 13 at 13:54
@RoVo I agree with your 1). for 4), the variable could be as complex as needed to make the pb disappear (ex:
uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406
... )– Olivier Dulac
May 13 at 13:54
1
1
Sure sure, it's not very likely, but anyways it might introduce a security issue later on. And then you might want to remove that string before printing to file ;-)
– pLumo
May 13 at 13:55
Sure sure, it's not very likely, but anyways it might introduce a security issue later on. And then you might want to remove that string before printing to file ;-)
– pLumo
May 13 at 13:55
|
show 1 more comment
If order of output must be: stdout then stderr; there is no solution with redirection only.
The stderr must be stored to a temporal file
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
Description:
The only way to redirect one output (an fd like stdout or stderr) to two files is to reproduce it. The command tee
is the correct tool to reproduce a file descriptor content. So, an initial idea to have one output on two files would be to use:
... | tee file1 file2
That reproduces the stdin of tee to both files (1 & 2) leaving the output of tee still unused. But we need to append (use -a
) and only need one copy. This solve both issues:
... | tee -a file1 >>file2
To supply tee
with stdout (the one to repeat) we need to consume stderr directly out of the command. One way, if order is not important (order of output will (most probably) be preserved as generated, whichever is output first will be stored first). Either:
cmd 2>>file1 | tee -a file2 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
Option 2 works only in some shells. Option 3 uses an additional subshell (slower) but use the file names only once.
But if stdout must be first (whichever order output is generated) we need to store stderr to append it to file at the end (first solution posted).
1
Or store in memory likesponge
does:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
– Stéphane Chazelas
May 14 at 11:15
add a comment
|
If order of output must be: stdout then stderr; there is no solution with redirection only.
The stderr must be stored to a temporal file
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
Description:
The only way to redirect one output (an fd like stdout or stderr) to two files is to reproduce it. The command tee
is the correct tool to reproduce a file descriptor content. So, an initial idea to have one output on two files would be to use:
... | tee file1 file2
That reproduces the stdin of tee to both files (1 & 2) leaving the output of tee still unused. But we need to append (use -a
) and only need one copy. This solve both issues:
... | tee -a file1 >>file2
To supply tee
with stdout (the one to repeat) we need to consume stderr directly out of the command. One way, if order is not important (order of output will (most probably) be preserved as generated, whichever is output first will be stored first). Either:
cmd 2>>file1 | tee -a file2 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
Option 2 works only in some shells. Option 3 uses an additional subshell (slower) but use the file names only once.
But if stdout must be first (whichever order output is generated) we need to store stderr to append it to file at the end (first solution posted).
1
Or store in memory likesponge
does:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
– Stéphane Chazelas
May 14 at 11:15
add a comment
|
If order of output must be: stdout then stderr; there is no solution with redirection only.
The stderr must be stored to a temporal file
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
Description:
The only way to redirect one output (an fd like stdout or stderr) to two files is to reproduce it. The command tee
is the correct tool to reproduce a file descriptor content. So, an initial idea to have one output on two files would be to use:
... | tee file1 file2
That reproduces the stdin of tee to both files (1 & 2) leaving the output of tee still unused. But we need to append (use -a
) and only need one copy. This solve both issues:
... | tee -a file1 >>file2
To supply tee
with stdout (the one to repeat) we need to consume stderr directly out of the command. One way, if order is not important (order of output will (most probably) be preserved as generated, whichever is output first will be stored first). Either:
cmd 2>>file1 | tee -a file2 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
Option 2 works only in some shells. Option 3 uses an additional subshell (slower) but use the file names only once.
But if stdout must be first (whichever order output is generated) we need to store stderr to append it to file at the end (first solution posted).
If order of output must be: stdout then stderr; there is no solution with redirection only.
The stderr must be stored to a temporal file
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
Description:
The only way to redirect one output (an fd like stdout or stderr) to two files is to reproduce it. The command tee
is the correct tool to reproduce a file descriptor content. So, an initial idea to have one output on two files would be to use:
... | tee file1 file2
That reproduces the stdin of tee to both files (1 & 2) leaving the output of tee still unused. But we need to append (use -a
) and only need one copy. This solve both issues:
... | tee -a file1 >>file2
To supply tee
with stdout (the one to repeat) we need to consume stderr directly out of the command. One way, if order is not important (order of output will (most probably) be preserved as generated, whichever is output first will be stored first). Either:
cmd 2>>file1 | tee -a file2 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
Option 2 works only in some shells. Option 3 uses an additional subshell (slower) but use the file names only once.
But if stdout must be first (whichever order output is generated) we need to store stderr to append it to file at the end (first solution posted).
edited May 13 at 22:04
answered May 13 at 21:53
IsaacIsaac
15.2k1 gold badge25 silver badges64 bronze badges
15.2k1 gold badge25 silver badges64 bronze badges
1
Or store in memory likesponge
does:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
– Stéphane Chazelas
May 14 at 11:15
add a comment
|
1
Or store in memory likesponge
does:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
– Stéphane Chazelas
May 14 at 11:15
1
1
Or store in memory like
sponge
does: (cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
– Stéphane Chazelas
May 14 at 11:15
Or store in memory like
sponge
does: (cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
– Stéphane Chazelas
May 14 at 11:15
add a comment
|
In the interests of diversity:
If your system supports /dev/stderr
, then
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
will work.
The standard output of the cmd
is sent to both the stdout and the stderr of the pipeline.
The standard error of the cmd
bypasses the tee
and comes out the stderr of the pipeline.
So
- the stdout of the pipeline is just the stdout of the
cmd
, and - the stderr of the pipeline is the stdout and stderr of the
cmd
,
intermixed.
It's then a simple matter of sending those streams to the correct files.
As with almost any approach like this (including Stéphane’s answer),file1
may get lines out of order.
add a comment
|
In the interests of diversity:
If your system supports /dev/stderr
, then
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
will work.
The standard output of the cmd
is sent to both the stdout and the stderr of the pipeline.
The standard error of the cmd
bypasses the tee
and comes out the stderr of the pipeline.
So
- the stdout of the pipeline is just the stdout of the
cmd
, and - the stderr of the pipeline is the stdout and stderr of the
cmd
,
intermixed.
It's then a simple matter of sending those streams to the correct files.
As with almost any approach like this (including Stéphane’s answer),file1
may get lines out of order.
add a comment
|
In the interests of diversity:
If your system supports /dev/stderr
, then
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
will work.
The standard output of the cmd
is sent to both the stdout and the stderr of the pipeline.
The standard error of the cmd
bypasses the tee
and comes out the stderr of the pipeline.
So
- the stdout of the pipeline is just the stdout of the
cmd
, and - the stderr of the pipeline is the stdout and stderr of the
cmd
,
intermixed.
It's then a simple matter of sending those streams to the correct files.
As with almost any approach like this (including Stéphane’s answer),file1
may get lines out of order.
In the interests of diversity:
If your system supports /dev/stderr
, then
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
will work.
The standard output of the cmd
is sent to both the stdout and the stderr of the pipeline.
The standard error of the cmd
bypasses the tee
and comes out the stderr of the pipeline.
So
- the stdout of the pipeline is just the stdout of the
cmd
, and - the stderr of the pipeline is the stdout and stderr of the
cmd
,
intermixed.
It's then a simple matter of sending those streams to the correct files.
As with almost any approach like this (including Stéphane’s answer),file1
may get lines out of order.
answered May 14 at 19:27
ScottScott
7,6525 gold badges30 silver badges54 bronze badges
7,6525 gold badges30 silver badges54 bronze badges
add a comment
|
add a comment
|
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f518655%2fhow-to-redirect-stdout-to-a-file-and-stdoutstderr-to-another-one%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown