wolis has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,

While running a script on a newly setup server I discovered that the scripts refused to run without the -w switch.

A good opportunity to clean up my old code I thought.

Then I discovered some unusual warnings:
1) Why does it warn: print() on closed filehandle OUT at wm-sql.pl line 123.

open(OUT,">>$sql_file"); print OUT localtime().' ^ '.$pid.' ^ '.$_[0]."\n"; close(OUT);
It looks open before I print and closed after to me.

2) Name "main::portalserver" used only once: possible typo at..

I define variables in one bit of code then use them in another 'required' file in a rather obscure but functional way.

Can I hide these warnings? (do I just have to do some dummy work on each to fool it or is there a smarter way?)

Thanks,

___ /\__\ "What is the world coming to?" \/__/ www.wolispace.com

Replies are listed 'Best First'.
Re: print() on closed filehandle..
by Roger (Parson) on Feb 03, 2004 at 04:49 UTC
    open(OUT,">>$sql_file"); print OUT localtime().' ^ '.$pid.' ^ '.$_[0]."\n"; close(OUT);

    That sounds like the open has failed. Did you define $sql_file variable? And you should do error checking after open:
    open OUT, ">>$sql_file" or die "Can not open $sql_file";

    I define variables in one bit of code then use them in another 'required' file in a rather obscure but functional way.

    Sounds like bad programming practise to me. Take a look at the following node on better programming practise:

  • Perl Programming guidelines/rules

    A cleaner approach I would take is to build a hash of variables, and pass the reference to the hash to the constructor / initializer of your module -
    use strict; use warnings; use MyModule; my %vars = ( 'foo' => 'bar', 'date' => '20040203', 'name' => 'roger', ... ); my $mymodule = MyModule->new(\%vars);

    And then in your module you refer to the variables by name.

      Ah.. thanks guys,

      Yes, that old 'functional' bit of code I require is long overdue for a re-write - if only I can find the time (sigh)

      And I'm so sorry to have troubled you on such a trivial thing re open().. Since its a new setup I didnt have the correct folder to write into.

      I mis-interpreted the warning thinking it was saying I had my lines of code the wrong way round :-) (which logically they were if the file was not opened in the first place)

      Keep up the good work!

      ___ /\__\ "What is the world coming to?" \/__/ www.wolispace.com
Re: print() on closed filehandle..
by davido (Cardinal) on Feb 03, 2004 at 05:28 UTC
    Did you look at the file afterward to see if it actually had new data appended to it?

    Always ALWAYS check for success/failure of your opens. It's easy....

     open(OUT, ">>$sql_file") or die "Guess what, it didn't work!\n$!";

    If I had to guess, I'd say that your script doesn't have proper permissions with the file you're trying to write to and open.

    To answer your second question, you can say, " no warnings qw/vars/; " in the appropriate section of code, and then restart them later. The warnings pragma gives pretty good flexibility.


    Dave

Re: print() on closed filehandle..
by antirice (Priest) on Feb 03, 2004 at 05:44 UTC

    Roger answered why your code produces these warnings. Now I'd like to share with you why it doesn't work without -w: you editted the scripts in Windows and didn't convert them when you moved them (ftp upload in binary?). Some possible solutions are:

    1. Remove all of the CR's. A simple way to do that is with:
      perl -i -pe's/\r$//' file.pl
    2. Provide a symbolic link called perl^M for your copy of perl.
    3. Just put a space behind perl in your sharp-bang line.

    However, I think this is a good thing that you've turned on warnings as it has made you aware of some bugs that may otherwise have gone unnoticed for a while.

    antirice    
    The first rule of Perl club is - use Perl
    The
    ith rule of Perl club is - follow rule i - 1 for i > 1

Re: print() on closed filehandle..
by ysth (Canon) on Feb 03, 2004 at 16:48 UTC
    Get rid of the "used only once" by putting an our $portalserver; in your code (doesn't have to be in any particular scope; just has to happen before the main script is done compiling).  Use use vars wq/$portalserver/; instead if on perl older than 5.6.0 or if the variable has a different package name (e.g. use use vars qw/$foo::bar/;).
      Ah.. so 'our' is like 'global' in other languages? (opposite of 'my')?
      ___ /\__\ "What is the world coming to?" \/__/ www.wolispace.com
        Not exactly. global variables just spring into existence when the compiler notices them, so our() doesn't really declare them, per se. our() serves a few different purposes. One is to get rid of the "used only once" warning (which is intended to help catch typos in variable names). If you run with use strict "vars"; turned on, you'll usually have to use our() on user variables native to a package but not qualified by a package (aka namespace). This is also intended to help catch typos in variable names.

        our() also will hide a my() variable for a certain scope:

        perl -we '$x = "global"; my $x = "local"; our $x; print $x' global
        Here there are two different $x variables; the global $x that lives in the symbol table for the main:: package, and a lexical $x that lives in a pad (a kind of temporary storage attached to each subroutine or source file (though one pad can have multiple variables of the same name with different scopes within the subroutine)). Normally in the scope of a my($var), $var will refer to the lexical variable. our($var) can be used to override that to the end of the enclosing block.