Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Execute function before exit of do() block

by gri6507 (Deacon)
on Jan 29, 2014 at 17:47 UTC ( [id://1072553]=perlquestion: print w/replies, xml ) Need Help??

gri6507 has asked for the wisdom of the Perl Monks concerning the following question:

Fellow monks,

I have two script, main and helper, where the latter is executed by the former using a do() statement. I would like to do something on abnormal terminations of the helper. I tried using an END {} block withing the helper to do that, but unfortunately it seems to only execute on completion of the main script.

Here is my main script

use warnings; use strict; my $doItScript = $ARGV[0]; unless (my $return = do $doItScript) { if ($@) { print "$doItScript: $@\n";} elsif (!defined($return)) { print "$doItScript: $!\n";} elsif (!$return) {print "could not execute $doItScript\n";} } print "Done with main\n";

Here is my helper script

use warnings; use strict; use Carp; END { print "Good bye\n"; } print "Hello\n"; croak "bad thing"; print "There\n"; 1;

As expected, the helper "There" message is not printed, but the "Good bye" message is printed only after "Done with main". How can I reverse the order of those two events?

Replies are listed 'Best First'.
Re: Execute function before exit of do() block
by moritz (Cardinal) on Jan 29, 2014 at 19:04 UTC

    One technique you can use is a "scope guard"; an object which goes out of scope when a scope is exited. When it goes out of scope, its reference count drops to zero and its DESTROY method is called:

    # slave.pl: use 5.014; use warnings; my $CleanExit = 0; { package My::ScopeGuard; sub DESTROY { return if $CleanExit; say 'cleaning up slave.pl'; } } # this is the object that will go out of scope my $guard = bless {}, 'My::ScopeGuard'; say 'doing something'; die "Oh Noez"; # or if everything works fine: $CleanExit = 1;

    Now we can test it likes this:

    $ perl -wE 'do "slave.pl"; say "Back in master"' doing something cleaning up slave.pl Back in master

    You can see that the cleanup happens before the the rest of the calling code.

      I've been thinking about this, too, prior to writing my $SIG{__DIE__} answer above.
      *sigh*
      Creating a sentinel object... slowly, the objectification creeps on every subject...

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

        Well, in Perl 6 there are are non-object options, like a LEAVE block that is called on every scope exit, or an UNDO block for unsuccessful scope exists.

        I wonder if those are possible (and worthy) to backport to perl 5...

        You could use clear or free magic if you wanted to avoid objects.
Re: Execute function before exit of do() block
by choroba (Cardinal) on Jan 29, 2014 at 17:51 UTC
    If you study the documentation of do, you can notice it behaves as eval. It means, you can check the problems in the calling script. If you want to check the problems in the called script, you can use eval:
    eval { print "Hello\n"; croak "bad thing"; print "There\n"; 1 } and print "Good bye\n";
    See also Try::Tiny.
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      My main script is generic and can "execute" many different types of helper scripts. Not all helper scripts need (or even can) act on the detected bad event. That is why the detection of the bad event needs to happen inside the helper script, rather than the main script. Your solution would not work in my case.
        Not all helper scripts need (or even can) act on the detected bad event. That is why the detection of the bad event needs to happen inside the helper script, rather than the main script.

        What would detection of the bad event (...) inside the helper script script give you, if that helper script cannot act on the detected bad event as you are saying? Error detection has to happen in the main script, checking the for $@ as you already do.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        Your solution would not work in my case.
        I proposed two solutions. Which one do you mean?
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: Execute function before exit of do() block
by Laurent_R (Canon) on Jan 29, 2014 at 18:25 UTC
    I do not know what your helper script is doing, but if the two scripts are independent, maybe you could use the system command to launch your second script and check the exit status of the child.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1072553]
Approved by boftx
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (4)
As of 2024-04-25 23:47 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found