How to save STDERR and STDOUT of a pipeline on a file? - bash

I'm running a pipeline of commands that have STDERR and STDOUT outputs. I want to save both outputs in a single log file.
This are my attempts to do it:
bash my_script.sh > log.txt #Only save STDOUT
bash my_script.sh > >(tee log.txt) 2> >(tee log.txt >&2) #The STDERR overwrite the STDOUT
I hope you can provide a simple solution to do this.
Thanks for your time!

How about just
bash my_script.sh > >(tee log.txt) 2>&1
Also if you want to append output if log.txt already exists, add -a option to tee
bash my_script.sh > >(tee -a log.txt) 2>&1
It's actually equivalent to bash my_script.sh 2>&1 | tee log.txt or bash my_script.sh 2>&1 | tee -a log.txt

bash my_script.sh > log.txt 2>&1
where 2>&1 redirects stderr to stdout

Related

Bash forwarding stdout, stderr and pipe to external program

I've a Bash command with runs a python script and produce outputs on stdout and stderror.
Normal and error logs are written to separate files with this command:
python3 file.py >> normal.log 2>> error.log
Additionally, stdout and stderr shall be forwarded to an external program (e.g. logToTelegram.sh):
python3 file.py 2>&1 | logToTelegram.sh
Is there a way to implement both during one execution, write log files (normal and error) and pipe stdout and stderror together to the program logToTelegram.sh?
This should do the trick:
( python3 file.py 2> >(tee -a error.log) > >(tee -a normal.log) ) | logToTelegram.sh
Note that 2> >(tee ...) has to be placed before > >(tee ...) for this to work correctly. For simplicity, both tee commands output to stdout, eliminating the need for 2>&1 before piping to logToTelegram.sh.
Or, to stay closer to the original code and to be more precise:
( python3 file.py > >(tee -a normal.log) 2> >(tee -a error.log >&2) ) 2>&1 | logToTelegram.sh
Here, the first tee outputs to stdout, while the second tee outputs to stderr, thus 2>&1 is required to send all output to logToTelegram.sh.

In a shell script, how to redirect stdout to console and both stdout and stderr to a file?

I need to redirect stdout to console along with stdout and stderr redirected to a file. This needs to be done inside a shell script.
I found the below code to redirect both to console and log file, now I need to remove stderr to console.
exec > >(tee -i "output.log") 2>&1
Could you please help me here?
Derived from this answer:
How do I get both STDOUT and STDERR to go to the terminal and a log file?
I tested the following code:
echo '' > out.log
exec 1> >(tee -a -i out.log) 2> >(tee -a -i out.log > /dev/null)
>&2 echo yay
echo nay
The STDERR content goes to file and not to console, and STDOUT goes to both.
I think you should launch it like this:
your-command 2>&1 | tee -i "output.log"
It will pipe both stdin and stderr to tee -i output.log, which will echo text before writing.
Or, to ignore stderr (pipe to /dev/null):
your-command 2>/dev/null | tee -i "output.log"
Or your command modified with /dev/null redirection:
exec > >(tee -i "output.log") 2>/dev/null
It'd be something like this, but you don't have to tee that second one.
exec 1> >( tee stdout.txt ) 2> stderr.txt
output 1 is tee'd so you see it on screen, and in stdout.txt
errors 2 just goes straight to stderr.txt

How run a command, show stderr on screen, and at the same time, save stderr in a file

I want to run a command, show stderr on screen and, at the same time, save stderr in a file.
In bash (or zsh), you can do this by redirecting stderr to tee via a process substitution:
somecommand 2> >(tee errors.log)
This command shows stdout and stderr on screen and saves stderr on /tmp/errors:
$ ( ls file_do_not_exist /bin/true 2>&1 1>&3 | tee /tmp/errors 1>&2; ) 3>&1

Redirect copy of stdout and stderr to one file, copy of just stderr to another file from within bash script

Note that I have reviewed both stackoverflow questions below, but my question is different:
redirect COPY of stdout to log file from within bash script itself
redirect stdout and stderr to one file, copy of just stderr to another
In attempting to do this, I have the following test.sh script:
#!/bin/bash
rm stdout_and_stderr.log
rm stderr.log
exec 2> >(tee -ia stderr.log >> stdout_and_stderr.log) 1> >(tee -ia stdout_and_stderr.log)
echo "stdout"
echo "stderr" >&2
The only problem is that stderr is not displayed to terminal:
$ ./test.sh > /dev/null
$ ./test.sh 2> /dev/null
$ stdout
My version of bash:
GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu)
Here is a solution that works:
#!/bin/bash
rm stdout_and_stderr.log
rm stderr.log
exec 2> >(tee -ia stdout_and_stderr.log >&2)
exec 2> >(tee -ia stderr.log >&2)
exec 1> >(tee -ia stdout_and_stderr.log)
echo "stdout"
echo "stderr" >&2
It can also be done in one line:
exec 1> >(tee -ia stdout_and_stderr.log) 2> >(tee -ia stdout_and_stderr.log >&2) 2> >(tee -ia stderr.log >&2)

how to redirect stdout and stderr to a file while showing stderr to screen?

The script should redirect all the output (stdout and stderr) to a log file, and only display stderr to the screen (notifying user if an error happens). The command tee may help but don't know how to write it.
Thanks.
P.S., thanks lihao and konsolebox for the answer, but is there a way to keep the output in order. For example:
$ cat test.sh
echo "to stdout..1"
echo "to stderr..1" >&2
echo "to stdout..2"
echo "to stderr..2" >&2
$ sh test.sh 2>&1 >test.log | tee -a test.log
to stderr..1
to stderr..2
$ cat test.log
to stdout..1
to stdout..2
to stderr..1
to stderr..2
Command: { sh test.sh 2> >(tee /dev/fd/4); } 4>&1 >test.log has the same output.
how about the following:
cmd args 2>&1 >logfile | tee -a logfile
You should map normal stdout to another file descriptor (4), make the file the default output, then use tee to redirect output to the new file descriptor through /dev/fd. Of course you'd need process substitution to pass stderr output to tee:
{ cmd args 2> >(exec tee /dev/fd/4); } 4>&1 >file
If you want to make a general redirection for the script, place this at the beginning of it:
exec 4>&1 >file 2> >(exec tee /dev/fd/4)
You can restore normal output with:
exec >&4 4>&-

Resources