in reply to Multiple actions triggered by failure to open a file

You can only specify a single command after || or or . To add a block, add a do or call a subroutine:

open my $log_FH, '>', './testlogifle.txt' or do { print "Failure to open log file.\n"; die "Failure to open log file.\n"; };
sub print_and_die { my ($message) = @_; print $message; die $message; } open my $log_FH, '>', './testlogifle.txt' or print_and_die("Failure to open log file.\n");
($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

Replies are listed 'Best First'.
Re^2: Multiple actions triggered by failure to open a file
by GreenLantern (Novice) on Jan 10, 2017 at 18:27 UTC

    So now i'm expereincing something new....it appears related to the || do.....

    #!/tps/bin/perl $logfilename = './test.log'; open (my $FH, '>', $logfilename) || die "CANNOT OPEN LOG"; print "\n\noutside FH\n\n"; select $FH; print "\n\n this is inside the FH\n\n"; select STDOUT; print "\n\n this is back outside the FH\n\n"; close($FH); $logfilename = './test2.log'; open (my $FH, '>', $logfilename) || do { print "test test test\n"; die "CANNOT OPEN LOG"; } print "\n\noutside FH\n\n"; select $FH; print "\n\n this is inside the FH\n\n"; select STDOUT; print "\n\n this is back outside the FH\n\n"; close($FH);

    when i run this just the first portion of it, before the second open file, select works fine. but when i instate the second open statement with the || do, i am given this error:

    syntax error at test.pl line 34, near "print"

    is there something wrong with my syntax or does do have some unintended consequence on output redirection? thanks

      do isn't a control structure, it needs a semicolon after the block.

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      G'day GreenLantern,

      I see ++choroba has provided a solution to your syntax error. You have other problems with your code which Perl will tell you about, if you ask it to, by including the strict and warnings pragmata.

      Consider this fairly innocuous looking piece of code.

      $ perl -E 'open my $fh, ">", "xxx"; close $fb; open my $fh, ">", "yyy" +' $

      As you can see, it runs without any apparent problems. However, it does in fact contain one of the problems in your posted code. I've introduced another problem which is easy to make: I typed one key adjacent to the one I wanted (i.e. a fairly basic typo we all can make from time to time). Now look what happens if I'd asked Perl to tell me about problems.

      $ perl -E 'use strict; use warnings; open my $fh, ">", "xxx"; close $f +b; open my $fh, ">", "yyy"' "my" variable $fh masks earlier declaration in same scope at -e line 1 +. Global symbol "$fb" requires explicit package name (did you forget to +declare "my $fb"?) at -e line 1. Execution of -e aborted due to compilation errors. ken@ganymede: ~/tmp $

      The first problem it reports is the same as you have in your code (except yours is $FH, not $fh). The second one is the typo I introduced: 'b' is adjacent to 'h' on the keyboard; the shape of those two characters is very similar, making the problem easy to overlook.

      The typo is easy to fix: s/b/h/. The other problem could be overcome by:

      • changing the name, e.g. call the second filehandle $fh2
      • or better, using meaningful names to start with, e.g. $xxx_fh and $yyy_fh
      • or even better, not using filehandles with global scope

      Here's one possible fix for both those problems:

      $ perl -E 'use strict; use warnings; { open my $fh, ">", "xxx"; } open + my $fh, ">", "yyy"' $

      Note that I could have fixed the typo but, as Perl closes filehandles when they go out of scope, I didn't need the close statement, and that problem just disappeared all by itself.

      Make a point of adding these lines to the start of all your scripts:

      use strict; use warnings;

      It's good that you're checking for I/O problems; however, you're providing no information about the problem. In two places you have:

      die "CANNOT OPEN LOG";

      That provides no feedback about why open failed or which log file had the problem. Perl provides $! which holds the reason for the failure; you already know the filename and need to provide that youself. Those die statements would've been better written something like:

      die "CANNOT OPEN LOG '$logfilename': $!";

      Hand-crafting your own die messages is both tedious and error-prone. This is another task you can just let Perl do for you with the autodie pragma. When you do need custom error handling, such as in your second open statement, you should take a copy of $! as early as possible (it could be changed by another statement in your custom handler), and turn off autodie functionality (i.e. with no autodie 'open';) in the smallest scope possible (e.g. add use autodie 'open'; right after the open statement).

      I notice you're selecting different filehandles before each print statement. Althougn print does use the currently selected filehande by default, you can specify the filehandle as part of the print statement. As STDOUT is the default filehandle, instead of

      select $fh; print "..."; select STDERR; print "..."; select STDOUT; print "...";

      you can just write

      print $fh "..."; print STDERR "..."; print "...";

      Going back to your various, previous problems with custom error handling, I think there's a better way to do this which makes your intent much clearer (and, therefore, subsequent reading and maintenance much easier). Consider something along these lines:

      my $open_ok = open my $fh, $mode, $filename; if (not $open_ok) { # custom error handling here }

      One final point about you're open statements. You typically want to append to log files, so use '>>' for the MODE; if you use '>' , you'll delete all previous log data.

      Putting all that together, your code above could be written like this (untested).

      #!/tps/bin/perl use strict; use warnings; use autodie; { my $logfilename = './test.log'; open my $fh, '>>', $logfilename; print $fh "..."; print "..."; } { my $logfilename = './test2.log'; no autodie 'open'; my $open_ok = open my $fh, '>>', $logfilename; use autodie 'open'; if (not $open_ok) { my $os_error = $!; print "Can't open '$logfilename': $os_error\n"; die "Can't open '$logfilename': $os_error"; } print $fh "..."; print "..."; }

      Update (fix): s/filehandle/filename/ in (what was) my $open_ok = open my $fh, $mode, $filehandle;

      — Ken

Re^2: Multiple actions triggered by failure to open a file
by GreenLantern (Novice) on Jan 10, 2017 at 16:07 UTC
    perfect! thank you!

      Or just a traditional "if":

      if (!open my $log_FH, '>', './testlogifle.txt') { print "Failure to open log file.\n"; die "Failure to open log file.\n"; }
        if (!open my $log_FH, '>', './testlogifle.txt') { print "Failure to open log file.\n"; die "Failure to open log file.\n"; }

        Note that the lexical  $log_FH in the quoted code is local to the if-block and cannot be used by anything except the open failure-handling code — probably not what GreenLantern intends. Instead, the lexical should be declared outside the block if it is ever to be used there.

        Also, this might be a good occasion to use the otherwise puzzling idiom I see sometimes in bioinformatics code: wrapping the open in an unless-block:

        my $log_FH; unless (open $log_FH, '>', './testlogifle.txt') { print "Failure to open log file.\n"; die "Failure to open log file.\n"; } do_something_with($log_FH); ...


        Give a man a fish:  <%-{-{-{-<