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

First, the XY Problem: I have some existing code whose output I want to capture, modify, and then write to a file. To do this, I'm reopening STDOUT to write to a scalar.

The problem is, the second time I do this, I get a warning ("Use of uninitialized value in open"). The first time, there's no problem. I'd like to know where the warning is coming from and how to avoid it.

What follows is a short program to demonstrate the problem. In production code, there's "or die" after every open and close. I've taken them out for this example to make it easier to read. Those calls do not fail when I run it.

use strict; use warnings; require v5.8; my $hello1 = dupe_and_back(); my $hello2 = dupe_and_back(); print $hello1, $hello2; sub dupe_and_back { print "call to dupe_and_back\n"; my $output; open my $old_stdout, '>&=', \*STDOUT; close STDOUT; # Use of uninitialized value in open at the following line open STDOUT, '>', \$output; print "Hello world\n"; open STDOUT, '>&=', $old_stdout; return $output; } __END__ call to dupe_and_back call to dupe_and_back Use of uninitialized value in open at perlmonks.pl line 21. Hello world Hello world

Thanks in advance.

Replies are listed 'Best First'.
Re: Use of uninitialized value in open second time but not first.
by varian (Chaplain) on Mar 30, 2007 at 19:32 UTC
    The problem is related to the use of memory files. Apparently Perl issues the uninitialized warning upon the second time (and third etc) a memory file is created.
    #!/usr/bin/perl -w my $output; print "first\n"; open (FH, '>', \$output); print FH "Hello world\n"; close(FH); $output=undef; print "second\n"; open (FH, '>', \$output); print FH "Hello world\n"; close(FH);

    Output:

    first second Use of uninitialized value in open at o4.pl line 10.
    Seems to me like an overzealous action by Perl's warning system but nothing alarming so far.
    Like said by the other monks you can set $output to the empty string as a workaround to avoid the warning alltogether.
Re: Use of uninitialized value in open second time but not first.
by sgifford (Prior) on Mar 30, 2007 at 18:41 UTC
    This looks to me like perl weirdness. Setting $output to an empty string when it's declared seems to eliminate the warning.
Re: Use of uninitialized value in open second time but not first.
by Jenda (Abbot) on Mar 31, 2007 at 00:14 UTC

    Would not it be easier to open() the scalar and select() the handle?

    open my $FH, '>', \$output; my $old_FH = select($FH); print "Hello world\n"; select($old_FH);
    Unless the code whose output you need to capture specificaly prints to STDOUT, this should work as well.

      Thanks for the suggestion!

      I actually don't know whether the code whose output I want to capture specifically prints to STDOUT (I didn't write it). I thought of the select solution too, but then I thought, "but what if it writes directly to STDOUT?" So I did this.

      The solution I had actually works but produces the warning. I mention the "real" problem just in case I'm doing something brainless.

Re: Use of uninitialized value in open second time but not first.
by mreece (Friar) on Mar 30, 2007 at 18:43 UTC
    i don't know why it only warns the second time, or why it warns at all, but
    my $output = '';
    silences it..
Re: Use of uninitialized value in open second time but not first.
by Bro. Doug (Monk) on Mar 31, 2007 at 17:48 UTC
    Excellent suggestions, monks.

    I don't really see the problem in the same way, however. If the problem is here:
    my $output; # this value is unintialized open my $old_stdout, '>&=', \*STDOUT; close STDOUT; # Use of uninitialized value in open at the following line open STDOUT, '>', \$output;
    It's not an issue of 'spitting warnings at the second opening of a memory file'. $output really is uninitialized, and STDOUT, when its called, is already initialized. So it actually spits a warning the first time.

    What I'm trying to say is that the warning is thrown more or less as expected. It's been pointed out that setting $output='' will fix the problem. Also... turning off 'use warnings' would probably silence it, but I wouldn't know because I never turn off warnings.

    I hope this helps.
    Bro. Doug :wq

      So it actually spits a warning the first time.

      Where does that warning go? It's not on my screen when I run it. As I see it, $output is uninitialized both times, but the warning is not printed the first time.

      I'm confused also because what I pass to open is a reference to $output which is always a real value regardless of whether $output is initialized or not.

        I see where I went wrong.

        To give a more concise answer to this question, I got the code to run and saw the results just as you reported. So I started experimenting.

        I noticed there are a lot of operations on references happening here, which makes me leery when you're mucking with global symbols (STDOUT, for instance). So I took $output and gave it persistence in scope:
        our $output ; # changed 'my' to 'our'
        The problem went away.

        By the way, I agree with the monks who suggested using select().

        Peace, monks.
        Bro. Doug :wq
Re: Use of uninitialized value in open second time but not first.
by GrandFather (Saint) on Jun 05, 2007 at 01:11 UTC

    The issue seems real. Consider:

    use strict; use warnings; wibble (); wibble (); sub wibble { my $unicode16Str; open my $UTF, '>:encoding(UTF-16LE)', \$unicode16Str; print $UTF "Wibble"; close $UTF; }

    Generates:

    Use of uninitialized value in open at noname1.pl line 10.

    for the second call. However changing my $unicode16Str; to my $unicode16Str = '';

    runs clean. Making $unicode16Str global to the sub is also fine. A closure issue perhaps?


    DWIM is Perl's answer to Gödel
      open my $UTF, '>:encoding(UTF-16LE)', \$unicode16Str;

      That may be a completely different issue.

        I don't think so. The warning is only issued for the second open. The code otherwise works as expected. Initialising the output buffer ($unicode16Str) resolves the issue. Making the output buffer global also resolves the issue.


        DWIM is Perl's answer to Gödel
Re: Use of uninitialized value in open second time but not first.
by pmorch (Initiate) on Jul 19, 2007 at 11:22 UTC
    Here is a shorter reproducing script. I wrote it before I decided to google for this problem... :D
    #!/usr/bin/perl -w use strict; foreach (0..1) { my $scalar; open my $h, ">", \$scalar; print "End of $_\n"; }
    Similar to the OP, this generates a warning the second but not the first time through the loop.

    But unlike the OP, it just fiddles with a my $h handle, not STDOUT or anything like that.

    Similar to the OP, initializing with my $scalar = '' removes the warning, but isn't this a perl bug? Shouldn't $scalar be in the same state both times through the loop when it isn't initialized?