Need output of script on screen and file with correct return status of the called script.

Hi,

I am trying to capture logs of the script in the file as well as on the screen. I have used exec and tee command for this. While using exec command I am getting the correct output in the file but, script output is not getting displayed on the screen as it get executed.

Below is my sample script. (I have deliberately introduced an error in the script to check exit status).

$ cat 1.sh
echo "Hi"
echo "how"
echo "are"
echo "you?"
echo "I am fine.."
cp l c
a=`echo $?`
echo $a
if [ $a -ne 0 ]
then
        echo "error in script1"
        exit 1

fi
$


$ cat 2.sh
#!/bin/bash
exec 1> ./2.log 2>&1
echo "Script 2 started"
sh 1.sh
echo $?
echo "This is part of script2"
$

Output:

$ sh 2.sh
$


$ ls -ltr 2.log
-rw-rw-r--  1 dbcomdev dbcomdev 137 Nov 13 02:48 2.log
$


$ cat 2.log
Script 2 started
Hi
how
are
you?
I am fine..
cp: cannot stat `l': No such file or directory
1
error in script1
1
This is part of script2
$ 

I have tried to use tee command with exec command but it is giving me error.

$ cat 4.sh
#!/bin/bash
exec 1> >(tee -a ./2.log) 2>&1
echo "Script 2 started"
sh 1.sh
echo $?
echo "This is part of script2"
$

Output:

$ sh 4.sh
4.sh: line 2: syntax error near unexpected token `>'
4.sh: line 2: `exec 1> >(tee -a ./2.log) 2>&1 '
$

I have also tried to use the tee command, but I am loosing exit status of the script called within main script.

$ cat 3.sh
#!/bin/bash
echo "Script 2 started"
sh 1.sh 2>&1 | tee -a ./2.log
echo $? | tee -a ./2.log
echo "This is part of script2" | tee -a ./2.log
$

Output:

$ sh 3.sh
Script 2 started
Hi
how
are
you?
I am fine..
cp: cannot stat `l': No such file or directory
1
error in script1
0
This is part of script2
$
$ cat 2.log
Hi
how
are
you?
I am fine..
cp: cannot stat `l': No such file or directory
1
error in script1
0
This is part of script2
$

Please advise how to get script output on screen as well as within file without loosing exit status.
I am using Linux machine.

The exec > >(tee...) works with my GNU bash, version 4.3.30(1) - maybe your bash is older? To get at the exit codes of commands in a pipe, try ( man bash )

whose availability may also depend on your version.

1 Like

Thanks for your reply. But, it is not working for me.
My unix version is:


$ uname -a
Linux XXXXX 2.6.9-89.35.1.ELsmp #1 SMP Tue Jan 4 22:29:01 EST 2011 x86_64 x86_64 x86_64 GNU/Linux

What be your bash version?

Can you please advise, how can I check bash version?

man bash

1 Like

You can set the return code to a variable so you can reuse it at any later time again.

Example - 1.sh

#!/bin/bash
echo "I'm script: $0" | tee -a ./1.log
[[ $UID -eq 34567 ]]
RET=$?
echo "The exit code was $RET, and now it can be re-used"
echo "Returned: $RET" | tee -a ./1.log

echo "Cat'ing:"
cat 1.log

Output:

sh 1.sh 
I'm script: 1.sh
The exit code was 1, and now it can be re-used
Returned: 1
Cat'ing:
I'm script: 1.sh
Returned: 1

Hope this helps

1 Like

Thanks.
My bash version is:

$ echo $BASH_VERSION
3.00.15(1)-release

---------- Post updated at 07:06 PM ---------- Previous update was at 06:58 PM ----------

Thanks for your reply.
I am calling child script from parent script and I want to capture the exit status of the child script into main script. Can I store exit status of child script in variable and use it in parent script?

I know that, we can export variable from parent script and use its value in child script but does it work other way?

That case is about the same:

sh 2.sh
RET=$?

Or likewise:

sh 2.sh
RET2=$?

sh 3.sh
RET3=$?

or even:

for script in 2.sh 3.sh;do
    sh $script
    RET=$?
    echo "$script returned: $RET" | tee -a $script.log
    echo "$script returned: $RET" | tee -a allscripts.log
done

Not unless you export the variable, in which case, they must not have the same name, or you can just fetch the latest 'output/export'.
However, you could read the logfile for sure.

hth

I want to catch the output of the $script in log file (both stdout and stderr). How can I do that?

If I use tee command to capture both stdout and stderr like below, I loose the exit status.

sh $script 2>&1 | tee -a $script.log

I wrote a database backup script where I have exec in the script redirecting stdout and stderr in the script to a log file. Hence, when I run the script I don't see any output. But I can run the script as "nohup ./myscript.sh &" then I just tail -f on the log file to see exactly what it is doing. I tried using tee in the past to split the output, but could not get it working either. Maybe a newer bash version would work fine...

What i ment was:

...
    sh $script
    RET=$?
    echo "$script returned $RET just fined... regular output to terminal"
    echo "$script returned $RET" >> common.log
    ....
    echo "$script returned: $RET" | tee -a $script.log
    echo "$script returned: $RET" | tee -a allscripts.log
...
1 Like

Thanks.

Suppose we do not have control over the script which we are calling $script in this case. And it has only echo commands and it is not saving output to any file, only displaying output on terminal. But, we need to capture whatever output of echo command it is displaying in the main script (from where we are calling $script ) on screen terminal as well as in the file. Then how can we do it?

This is really the preferred way to do it -- from the outside. Complicated schemes with pipes, tees, and fifos are liable to break down, subject to deadlocks, and can make your script dependent on a terminal: Untrustworthy and not worth the trouble. Even 99% success is not good enough. Putting in pipes also messes up the ordering, increases overhead manyfold, and can screw up your terminal prompt afterwards.

When redirecting it from the outside through tee, since you are using BASH, just check the script's return status in PIPESTATUS:

$ true | false | true | false
$ echo "${PIPESTATUS[0]} ${PIPESTATUS[1]} ${PIPESTATUS[2]} ${PIPESTATUS[3]}"
0 1 0 1

$
command 2>&1 | tee -a logfile
if [[ "${PIPESTATUS[0]}" -ne 0 ]]
then
        echo "command had an error"
fi

PIPESTATUS is even updated for a single command, so ${PIPESTATUS[0]} remains safe either way, as long as you're using BASH.

1 Like

Thanks Corona688.
RudiC did recommend me PIPESTATUS, but I was not sure how to use it.

I was able to get exit status of sh 1.sh result with the help of PIPESTATUS and using tee is helping me to show output on screen and saving in the file.

sh 1.sh 2>&1 | tee -a ./2.log
echo "Pipestatus1 : ${PIPESTATUS[0]}, Pipestatus2: ${PIPESTATUS[1]}" | tee -a ./2.log

Again, many thanks to RudiC,gandolf989,sea and Corona688 for your help.