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 <[email protected]> <[email protected]>
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'
signature.asc
Description: Digital signature
