1

I have got following simple shell script, in which I am trying to send STDERR & STDOUT to both screen and log it in a file(test.log). Also, while exiting I am trying to exit with appropriate exit codes.

In this code, I would expect it to echo first message (within the block) and exit. But, it is echoing both the statements and always exit with 0.

$ cat test.sh
#!/bin/ksh

n_exitstatus=0

{
  n_exitstatus=1
  echo "Inside block : $n_exitstatus"
  exit $n_exitstatus
}  2>&1 | tee -a test.log

echo "Before last exit : $n_exitstatus"
exit $n_exitstatus
$ sh test.sh
Inside block : 1
Before last exit : 0
$ echo $?
0

How to amend this script to exit just after echo'ing first statement (to be logged in both screen and file) ?

migrated from stackoverflow.com May 29 '15 at 11:29

This question came from our site for professional and enthusiast programmers.

2

You use the inner code block in a pipe. This forces the shell the run a sub shell. Exit only leaves the function. If you remove the pipe | tee -a test.log it should work as you expected.

So the easiest solution would be remove the pipe from the block and put it behind the inner echo command.

You could also create a function using the block as body, execute it and use the return value to decide to exit before going furter in the outside code.

Edit Here's a useful link: http://www.bolthole.com/solaris/ksh-functions.html

  • 1
    Not the clearest description (specifically function isn't helpful or correct here) but correct nonetheless. The issue here is that segments of a pipeline are executed in a sub-shell and so the first exit does not propagate to the parent shell. – Etan Reisner May 27 '15 at 12:41
  • @EtanReisner Yep, you are right. I was thinking on the solution to use a function when I gave the explanation. (I'm a man. I am not able to do multiple tasks at a time.) It's executed in a sub shell without spawning a new process. I checked this with echo $$ inside and outside of the block. Both time the same process id. I'm not sure but, I expect the sub shell to have its own $<vars>. – Peter Paul Kiefer May 27 '15 at 15:17
  • 1
    $$ is treated specially by bash in a sub-shell (documented in the section on $ if you look) you need $BASHPID (bash 4.0+) to see the sub-shell pid. – Etan Reisner May 27 '15 at 15:21
  • @EtanReisner I tried it. It worked. Lessons learned. – Peter Paul Kiefer May 27 '15 at 16:13
1

This is closely related to this question: Is there a way to write a bash function which aborts the whole execution, no matter how it is called?

Implementing the solution given by the accepted answer, we have this:

$ cat test.ksh
#!/bin/ksh

trap 'exit $n_exitstatus' TERM

SCRIPT_PID="$$"

n_exitstatus=0

{
    n_exitstatus=1
    echo "Inside block: $n_exitstatus"

    kill -s TERM $SCRIPT_PID

}  2>&1 | tee -a test.log

echo "Before last exit: $n_exitstatus"
exit $n_exitstatus
$ chmod +x test.ksh
$ ./test.ksh
Inside block: 1
$ cat test.log
Inside block: 1

The only thing not quite right still is that the exit status of the script is 0, not 1. This is because the exit happens from the outer scope where $n_exitstatus is zero.

Your Answer

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