On Thu, Mar 21, 2013 at 11:12:54PM +0100, Dominik Danter wrote:
> Hi I just don't understand the perlfaq example. All I want is to capture 
> output
> of an external command's stdout and stderr. Here is what I've tried:
> 
> sub get_exit() {

Careful with those parens. You may not realize, but that means
something special to Perl. It's called a prototype, and what
you're telling Perl is that get_exit accepts no arguments. This
matters because it will determine what things like this do:

    get_exit $exit_status, $std_out, $std_err;

Without a prototype it means what you think:

    get_exit(-1, $std_out, $std_err);

With an empty prototype as you have it, it actually means:

    get_exit() 1, $std_out, $std_err;
    #          ^ Syntax error. Operator expected.

Syntax error. It doesn't make sense. However, if you do happen to
have an operator there, such as + or -:

    get_exit -1, $std_out, $std_err;

Now it is syntactically correct, but doesn't do what you want it
to. Instead it means:

    get_exit() - 1, $std_out, $std_err;

So get_exit gets no arguments, 1 is subtracted from the return
value (which is a hash reference) as a number, and finally the
comma operators ultimately result in $std_err in a void context.
The warnings pragma will give you a bunch of warnings for this.

You shouldn't use a prototype unless you want built-in semantics
(i.e., so you can call your sub without parenthesis and still
have the right arguments passed to it). See `perldoc perlsub' for
all the details. Getting them right can be complex. There's no
real need for them though if you call your subs with parens.

So this should be:

    sub get_exit {

>     my ($exit_status, $std_out, $std_err) = @_;
>     my %error_codes = (
>         1024 => 'uid already exists',
>         256  => 'not root',
>         0    => 'success',
>     );
>     my $message = $error_codes{$exit_status};
>     return {
>         message     => (defined $message ? $message : 'unknown exit status'),
>         exit_status => $exit_status,
>         std_out     => (defined $std_out ? $std_out : 'no standard output
> produced'),
>         std_err     => (defined $std_err ? $std_err : 'no error output
> produced'),
>     };
> }
> 
> sub change_id {
>     my %command = (
>         uid => 'usermod --uid',
>         gid => 'usermod --gid',
>     );
>     my ($type, $username, $new_id) = @_;
>     my ($std_in, $std_out, $std_err, $exit_status);
>     eval {
>         my $pid = open3($std_in, $std_out, $std_err,
>                         "$command{$type} $new_id $username");
>         waitpid( $pid, 1);
>         $exit_status = $? >> 8;
>     };
>     return &get_exit($exit_status, $std_out, $std_err );

That bit above about prototypes doesn't apply when you call
subroutines with &, which may well be why you're using it in the
first place (otherwise you'd get a syntax error), but you
shouldn't be calling a subroutine with & anyway unless you
intentionally want to ignore the prototype. In this case, the
prototype shouldn't be there anyway, so there's no good reason to
use &. Once you get rid of the prototype you can call it
normallly:

    return get_exit($exit_status, $std_out, $std_err);

> }
> 
> 
> print Dumper(user::change_id('uid','bla',997));
> 
> 
> Here is my output:
> Use of uninitialized value $exit_status in hash element at user.pm line 31.
> $VAR1 = {
>           'std_err' => 'no error output produced',
>           'std_out' => \*Symbol::GEN1,
>           'exit_status' => undef,
>           'message' => 'unknown exit status'
>         };
> 
> 
> The command should fail since it lacks required permission, but I'd like to
> handle the error messages gracefully.

Regards,


-- 
Brandon McCaig <bamcc...@gmail.com> <bamcc...@castopulence.org>
Castopulence Software <https://www.castopulence.org/>
Blog <http://www.bamccaig.com/>
perl -E '$_=q{V zrna gur orfg jvgu jung V fnl. }.
q{Vg qbrfa'\''g nyjnlf fbhaq gung jnl.};
tr/A-Ma-mN-Zn-z/N-Zn-zA-Ma-m/;say'

Attachment: signature.asc
Description: Digital signature

Reply via email to