bug-bash
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]