in reply to Re: Multiple actions triggered by failure to open a file
in thread Multiple actions triggered by failure to open a file

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

Replies are listed 'Best First'.
Re^3: Multiple actions triggered by failure to open a file
by choroba (Cardinal) on Jan 10, 2017 at 18:48 UTC
    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,
Re^3: Multiple actions triggered by failure to open a file
by kcott (Archbishop) on Jan 11, 2017 at 00:49 UTC

    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