Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: open or [block of code]?

Tags:

perl

I'm running script A which feeds ARGV containing the path to a file to perl script B. This is done by a

local @ARGV = ($file, $file2, etc.);
do scriptB.pl or die "scriptB has failed";

Script B then tries to open the file:

open( my $fh_file, "<", $file )  
  or die "Could not open file '$file' $!"; 

However, if the file is missing I do not get the message quoted after "or die" in B. Instead I get the do scriptB.pl or die message in A. If I remove the "or die" from A, the script continues after B silently dies as if nothing went wrong.

I was wondering if there was any way to get B to print its die message?

Better yet, what is the best way to have B run a block of code after it fails to open the file? Said code would for example write to a separate file listing which files were missing so that the user may easily track down such errors.

#something like
open( my $fh_file, "<", $file) or { 
print "the file could not be found";
die;
}

The only thing I've found searching the net for help was someone mentioning a "or do {}", but this is giving me strange syntax errors so I am not sure if I'm using it right.

like image 403
Zyzyx Avatar asked Mar 10 '17 10:03

Zyzyx


People also ask

What is Open command in Perl?

Perl open file function You use open() function to open files. The open() function has three arguments: Filehandle that associates with the file. Mode : you can open a file for reading, writing or appending. Filename : the path to the file that is being opened.

How many arguments does open take?

Most often, open gets invoked with three arguments: the required FILEHANDLE (usually an empty scalar variable), followed by MODE (usually a literal describing the I/O mode the filehandle will use), and then the filename that the new filehandle will refer to.


3 Answers

If you want to continue to use the open(...) or ... syntax, then you could use do.

open my $fh, '<', $file or do {
  ...
};

But I think it's probably clearer to switch to if

if (! open my $fh, '<', $file) {
  ...
}

Or even unless

unless (open my $fh '<', $file) {
  ...
}
like image 186
Dave Cross Avatar answered Nov 01 '22 01:11

Dave Cross


I think you'll get clearer code with fewer gotchas if you put script B into a module, and load it with use or require and call the function(s) in there directly with clear parameters.

What you're missing here is that do involves an eval behind the scenes, and that results in the exception confusion. You can more or less avoid that confusion by moving your script B code into a function in a module, and calling it.

(Also, perl 5.26 will have a slight hiccup with do wherein the current directory will be removed from the directory lookup, due to security concerns. use and require have the same hiccup, but this may be less surprising since you should put your module into a path you explicitly get into the @INC load path.)

like image 45
Tanktalus Avatar answered Nov 01 '22 01:11

Tanktalus


die doesn't print a message; die throws an exception. When you catch that exception you don't do anything with the message passed to die. Replace

local @ARGV = ($file, $file2, etc.);
do scriptB.pl or die "scriptB has failed";

with

local @ARGV = ($file, $file2, etc.);
do scriptB.pl or die "scriptB has failed: ". ( $@ || $! );
like image 38
ikegami Avatar answered Nov 01 '22 01:11

ikegami