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'
signature.asc
Description: Digital signature