Perl: After a successful system call, “or die” command still ends script

跟風遠走 提交于 2019-12-03 18:01:47

问题


I am using the following line to make a simple system call which works:

system ("mkdir -p Purged") or die "Failed to mkdir." ;

Executing the script does make the system call and I can find a directory called Purged, but the error message is still printed and the script dies. What is wrong with my syntax?


回答1:


That would be a little confusing, wouldn't? - Leonardo Herrera on Ikegami's answer

Yes, it is confusing that the system command inverts true and false in Perl, and creates fun logic like this:

if ( system qw($command) ) {
    die qq(Aw... If failed);
}
else {
    say qq(Hooray! It worked!);
}

But, it's understandable why the system command does this. In Unix, an exit status of zero means the program worked, and a non-zero status could give you information why your system call failed. Maybe the program you were calling doesn't exist. Maybe the program sort of worked as expected. For example, grep returns an exit code of 1 when grep works, but there were no matching lines. You might want to distinguish when grep returns zero, one, or a return code greater than one. (Yes, I know it's silly to use a system call to grep in a Perl program, but that's the first example I could think of).

To prevent casual confusion, I create a variable that holds the exit status of my system command instead of testing the output of system directly:

my $error = system qw($command);
if ($error) {
    die qq(Aw... It failed);
}
else {
    say qq(Hooray! It worked!);
}

It's completely unnecessary, and people who work with Perl should know that system reverses Perl's definition of true and false, but if I hadn't had my coffee in the morning, I may miss it as I go over someone else's code. Doing this little step just makes the program look a bit more logical.

The Perldoc of system give you code that allows you to test the output of your system command to see exactly what happened. (If there was an error, or a system interrupt signal killed the system call). It's nice to know if you need to interrogate your system return value to figure out what went wrong.




回答2:


system returns the exit status of the command it calls. In shell, zero exit status means success. You have to invert the logic:

0 == system qw(mkdir -p Purged) or die "Failed to create the dir\n";



回答3:


system returns 0 on success, so you want and rather than or.

See also: use autodie qw( system );




回答4:


To add what hasn't been mentioned but what comes with it and can quietly mess things up.

The system's return of 'zero-or-not' only tells whether the command itself executed successfully, by shell or execvp; the 0 does not mean that the command succeeded in what it was doing.

In case of non-zero return you need to unpack $? for more information; see system for how to do this. For one, the command's actual exit code is $? >> 8, what the executed program was designed to communicate at its exit.

Altogether you may want to do something to the effect of

sub run_system {
    my ($cmd, @other_agrs) = @_;             # may do more via @other_args

    my ($cmdref, $sys_ret) = (ref $cmd, 0);  # LIST or scalar invocation?
    if ($cmdref eq 'ARRAY') {
        $sys_ret = system(@$cmd);
    }
    elsif (not $cmdref) {
        $sys_ret = system($cmd);
    }
    else { Carp::carp "Invocation error, got $cmdref" }

    return 1 if $sys_ret == 0;

    # Still here? The rest is error handling.
    Carp::carp "Trouble with 'system($cmd)': $?";
    print "Got exit " . ($? >> 8) . " from $cmd\n";
    return 0;  # or die (but then design changes)
}

This can be done merely as system == 0 or do { ... }; or such right in the code, but this way there's a little library, where we can refine error handling more easily, eventually decide to switch to a module to manage external commands, etc. Also, being a user-level facility now it makes sense that it returns true on success (we aren't changing system's design).

Additionally in this case, mkdir -p is meant to be quiet and it may not say anything when it cannot do its thing, in some cases. This is by design of course, but one should be aware of it.




回答5:


A one-line solution:

system("if printf '' > tmp.txt; then exit 1; else exit 0; fi ;") or die("unable to clobber tmp.txt");


来源:https://stackoverflow.com/questions/22762710/perl-after-a-successful-system-call-or-die-command-still-ends-script

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!