[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: bash trap techniques for group-command in a pipeline
From: |
john.ruckstuhl |
Subject: |
Re: bash trap techniques for group-command in a pipeline |
Date: |
Tue, 24 May 2011 20:00:50 -0000 |
User-agent: |
G2/1.0 |
Solution... this works nicely:
# print opening html
echo "<PRE>"
# on error, print msg and exit $STATUS
trap myERRhandler ERR
myERRhandler () {
local STATUS=$?
printf "Trouble: trapped ERR, exiting %s\n" $STATUS >& 2
exit $STATUS
}
# on exit, print closing html
trap myEXIThandler EXIT
myEXIThandler () {
echo "</PRE>"
}
mySubshellERRhandler () {
local STATUS=$?
exit $STATUS
}
myreturn() { return $1; }
echo cmd1
set -o pipefail
{
trap mySubshellERRhandler ERR
echo cmd2
echo "cmd3 (with exit code 6)"; myreturn 6
echo cmd4
} | tr a-z A-Z
echo cmd5
Regards,
John Ruckstuhl
On Apr 2, 12:50 pm, "john.ruckstuhl" <john.ruckst...@gmail.com> wrote:
> Summary: I don't see the best way to (in bash) trap/handle an ERR
> inside
> a group-command "{}" that is in a pipeline. I have a way that seems
> to
> work, see "(F)", but little confidence that it's the best way, and
> some
> suspicion that the overall effort is misguided.
>
> Detail:
> I'd like to trap and handle trouble during a bash script.
> By trapping ERR, I am successful handling trouble -- when commands
> are
> simple and not part of a pipeline.
> (A)
> cmd1; cmd2; trouble; cmd4; cmd5
>
> But I'd like to also filter the output of these commands...
> My trap scheme successfully handles
> (B)
> cmd1; { cmd2; trouble; cmd4; }; cmd5
> but fails to handle
> (C)
> cmd1; { cmd2; trouble; cmd4; } | filter; cmd5
>
> (I've also explored killing $$ (see (D)), which exits at the right
> place
> but doesn't return the proper status)
>
> Is this an expected limitation?
> Is there a workaround?
>
> Ahhh, further reading & research informs me of "pipefail", and leads
> me
> to set another trap inside the "{}".
> So, now (F) seems to work for me...
> Any comments will be appreciated -- Is there a better way?
> Or perhaps there are uncaught conditions and I've developed a false
> sense of security?
> See below for simple test script demonstrating implementations A - F,
> with cmd3 returning non-zero (or zero).
>
> My bash is version 3.2.51(24)-release (i686-pc-cygwin)
> Demonstrate as follows...
> 1st arg is the implementation variant,
> 2nd arg is the exit status of the middle command.
>
> # define simple wrapping function for "try" script
> $ mytry () { ./try $1 $2; echo dbg: script exit status: $?; }
>
> # (A) This works. The implementation of (A) is:
> # trap myERRhandler ERR
> # trap myEXIThandler EXIT
> # cmd1; cmd2; cmd3; cmd4; cmd5
>
> $ mytry A 0 # third cmd in series returns 0
> $ mytry A 6 # third cmd in series returns 6, so abend immediately
>
> # (B) This works. The implementation of (B) is:
> # trap myERRhandler ERR
> # trap myEXIThandler EXIT
> # cmd1; { cmd2; cmd3; cmd4; }; cmd5
>
> $ mytry B 0
> $ mytry B 6
>
> # (C) This doesn't abend when it should. The implementation of (C)
> is:
> # trap myERRhandler ERR
> # trap myEXIThandler EXIT
> # cmd1; { cmd2; cmd3; cmd4; } | filter; cmd5
>
> $ mytry C 0
> $ mytry C 6
>
> # (D) This abends when it should, but on trouble, script exits 0
> # trap myERRhandler ERR
> # trap myEXIThandler EXIT
> # cmd1
> #
> # trap myERRhandler HUP
> # { cmd2 && cmd3 && cmd4 || kill -HUP $$; } | filter
> #
> # cmd5
>
> $ mytry D 0
> $ mytry D 6
>
> # (E) This abends when it should, but on trouble, runs myERRhandler
> twice.
> # trap myERRhandler ERR
> # trap myEXIThandler EXIT
> # set -o pipefail
> # cmd1; { trap myERRhandler ERR; cmd2; cmd3; cmd4; } | filter;
> cmd5
>
> $ mytry E 0
> $ mytry E 6
>
> # (F) This seems to work... :)
> # trap myERRhandler ERR
> # trap myEXIThandler EXIT
> # set -o pipefail
> # cmd1
> # { trap myOtherERRhandler ERR; cmd2; cmd3; cmd4; } | filter
> # cmd5
>
> $ mytry F 0
> $ mytry F 6
>
> where try contains:
> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
> #! c:\cygwin\bin\bash
>
> # print opening html
> echo "<PRE>"
>
> # on error, print msg and exit $STATUS
> trap myERRhandler ERR
> myERRhandler () {
> STATUS=$?
> echo "dbg: entered myERRhandler() -- (on error, print msg and exit
> $STATUS)"
> echo "trouble..."
> exit $STATUS
>
> }
>
> # on exit, print closing html
> trap myEXIThandler EXIT
> myEXIThandler () {
> echo "dbg: entered myEXIThandler() -- (on exit, print closing
> html)"
> echo "</PRE>"
>
> }
>
> myreturn() { return $1; }
>
> echo cmd1
>
> case $1 in
> A)
> # THIS WORKS
> echo cmd2
> echo "cmd3 (with exit code $2)"; myreturn $2
> echo cmd4
> ;;
>
> B)
> # THIS WORKS
> {
> echo cmd2
> echo "cmd3 (with exit code $2)"; myreturn $2
> echo cmd4
> }
> ;;
>
> C)
> # THIS DOESN'T ABEND WHEN IT SHOULD
> {
> echo cmd2
> echo "cmd3 (with exit code $2)"; myreturn $2
> echo cmd4
> } | cat
> ;;
>
> D)
> # THIS ABENDS WHEN IT SHOULD, BUT ON TROUBLE, SCRIPT EXITS 0
> trap myERRhandler HUP
> {
> echo cmd2 &&
> echo "cmd3 (with exit code $2)" && myreturn $2 &&
> echo cmd4 ||
> kill -HUP $$
> } | cat
> ;;
>
> E)
> # THIS ABENDS WHEN IT SHOULD, BUT RUNS myERRhandler() twice
>
> # The return status of a pipeline is the exit status of the last
> # command, unless the pipefail option is enabled. If pipefail is
> # enabled, the pipeline's return status is the value of the last
> # (rightmost) command to exit with a non-zero status, or zero if
> # all commands exit successfully.
>
> set -o pipefail
> {
> trap myERRhandler ERR
> echo cmd2
> echo "cmd3 (with exit code $2)"; myreturn $2
> echo cmd4
> } | cat
> ;;
>
> F)
> # THIS ABENDS WHEN IT SHOULD, BUT RUNS myERRhandler() twice
>
> # The return status of a pipeline is the exit status of the last
> # command, unless the pipefail option is enabled. If pipefail is
> # enabled, the pipeline's return status is the value of the last
> # (rightmost) command to exit with a non-zero status, or zero if
> # all commands exit successfully.
>
> myInGroupERRhandler () {
> STATUS=$?
> echo "dbg: entered myInGroupERRhandler()"
> exit $STATUS
> }
>
> set -o pipefail
> {
> trap myInGroupERRhandler ERR
>
> echo cmd2
> echo "cmd3 (with exit code $2)"; myreturn $2
> echo cmd4
> } | cat
> ;;
>
> *)
> echo NOT IMPLEMENTED
> ;;
> esac
>
> echo cmd5
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: bash trap techniques for group-command in a pipeline,
john.ruckstuhl <=