开发者

Perl 'system' failure messages

开发者 https://www.devze.com 2022-12-29 16:23 出处:网络
Say I have this perl \"program\" called simple.pl: #!/usr/bin/perl use xyz; # xyz is bogus and doesn\'t exist

Say I have this perl "program" called simple.pl:

#!/usr/bin/perl
use xyz; # xyz is bogus and doesn't exist

And I also have this "program", call开发者_如何学Goed simple2.pl:

#!/usr/bin/perl
system("simple.pl");

my $abc = `simple.pl`;
printf("abc %s\n", $abc);

for both system and backtick, I get this message:

Can't exec "simple.pl": No such file or directory at scripts/perl/simple2.pl line 7.
Can't exec "simple.pl": No such file or directory at scripts/perl/simple2.pl line 9.

Not very useful for the user calling simple2.pl. Is there a way to get a more useful message?

Note. simple.pl does exist in the current directory. The real problem is that simple.pl doesn't compile. simple2 responds by saying simple doesn't exist. it's a misleading message.

If I had a way to even capture the compile message that would be a start.


This means system couldn't find an executable named "simple.pl" on your PATH. If your simple.pl is in the current directory, you could try to change "simple.pl" to "./simple.pl".

Actually, I don't see how to make this message more descriptive. If you were perl, how would you report this error?

BTW, I wouldn't try to run "simple2.pl" from inside of simple2.pl :)


Yes, check to see if the file exists and is executable, and if it isn't, print a more descriptive message.

unless (-ex $filename) {
  print "I am unable to execute file $filename.";
}


If perl say it can't find the file, then it can't find the file. And the problem is more your code. Look at this example.

sidburn@sid:~/perl$ cat test.pl 
#!/usr/bin/env perl
use strict;
use warnings;
use xyz;
sidburn@sid:~/perl$ cat test2.pl 
#!/usr/bin/env perl
use strict;
use warnings;
system('test.pl');
sidburn@sid:~/perl$ cat test3.pl 
#!/usr/bin/env perl
use strict;
use warnings;
system('./test.pl');

If you execute test2.pl you get:

sidburn@sid:~/perl$ ./test2.pl 
Can't exec "test.pl": No such file or directory at ./test2.pl line 4.

If you execute test3.pl you get:

sidburn@sid:~/perl$ ./test3.pl 
Can't locate xyz.pm in @INC (@INC contains: /home/sidburn/perl510/lib/5.10.1/i686-linux /home/sidburn/perl510/lib/5.10.1 /home/sidburn/perl510/lib/site_perl/5.10.1/i686-linux /home/sidburn/perl510/lib/site_perl/5.10.1 .) at ./test.pl line 4.
BEGIN failed--compilation aborted at ./test.pl line 4.

If you don't provide a relative or absolute path then perl lookup the command in your $PATH environment variable. If it is not there it can't find the file.

You need to provide "./" if it is in the current directory. But note "current directory" doesn't mean the directory where your script relies.

If you want the later then you probably want to do a

use FindBin;

with this you can do something like this:

#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use File::Spec::Functions;

my $exe = catfile($FindBin::RealBin, 'test.pl');

print $exe, "\n";
system($exe);

if you want to check if system returns correctly, you need to check the return value from the system() command or $? later that holds the value.

if ( $? != 0 ) {
    die "Cannot execute $exe.\n";
}

if you want to suppress messages from your program you need to redirect STDOUT, STDERR before starting your program with system().

Or use something like IPC::System::Simple Or IPC::Open3 (in the core).


Bonus points for enabling the warnings pragma! Have an upvote!

You want to use backticks or qx// to capture the output of an external program, not system. To substitute your own error message that will make sense to your users (more points for you!), then you might do something as in

#! /usr/bin/perl

use strict;
use warnings;
no warnings 'exec';

chomp(my $abc = `simple2.pl`);
if ($? == 0) {
  printf("abc %s\n", $abc);
}
else {
  die "$0: unable to calculate abc\n";
}

In case you're unfamiliar, $? is

$CHILD_ERROR
$?
The status returned by the last pipe close, backtick command, successful call to wait or waitpid, or from the system operator.

When $? is zero, it indicates success.

Remember that the warnings pragma is lexical, so rather than disabling the warning for the whole program, you might do it for just one sub:

sub calculate_abc {
  no warnings 'exec';

  # ...
}


If you are trying to execute something you know is a Perl script, why not invoke the interpreter directly rather than dealing with the system knowing how to execute the file?

my $file = 'simple.pl';

-e $file or die "file '$file' not found";

system "perl $file";
# or
print `perl $file`;

to run with the same installation of perl that is running your current script:

 system "$^X $file";   # or `$^X $file`

$^X is a special Perl variable that contains the file name of the running interpreter.


I had the exact same issue and figured out that perl wasn't installed. So the bash script was trying to execute the perl without an interpreter.

ls /usr/bin/perl


Try specifying the full path to the "simple.pl" file.

0

精彩评论

暂无评论...
验证码 换一张
取 消