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

I happened to notice an SoPW node where the OP's code passed $ARGV[0] to "open()" without checking if there was any value there, and I was intrigued about what Perl does with this sort of potential error. When I tried it out, I got a surprise:
#!/usr/bin/perl -w ## test 1: open for input open( I, $ARGV[0] ) or die $!; while(<I>) {print}
If I run that with no args (@ARGV empty), it sends a warning ("use of uninitialized value in open") and dies ("no such file or directory"). But then:
#!/usr/bin/perl -w ## test 2: open for output open( O, '>', $ARGV[0] ) or die $!; print O "this is a test\n";
If I run that with no args, I get no warning, no die, and no output file -- no output of any sort, anywhere.

Now, if I rephrase that second open statement to the 2-arg version --  open( O, ">$ARGV[0]" ) or die $!; -- then I get the expected warning and dying messages.

For that matter, if I convert the first test to use a three-arg open --  open( I, '<', $ARGV[0] ) -- I don't get any warning or die (and "use warnings" doesn't help, either).

I find this a bit disturbing (same behavior on macosx 5.8.1 and freebsd 5.8.6). Am I missing something?

update: special thanks to Transient for an illuminating tour of the relevant C functions in the Perl code base.

Replies are listed 'Best First'.
Re: 3-arg open() does not give warnings!?
by blazar (Canon) on Jul 15, 2005 at 13:23 UTC
    From perldoc -f open:
    As a special case the 3 arg form with a read/write mode and the third argument being "undef": open(TMP, "+>", undef) or die ... opens a filehandle to an anonymous temporary file. Also using "+<" works for symmetry, but you really should consider writing something to the temporary file first. You will need to seek() to do the reading.
    If FILEHANDLE is an undefined scalar variable (or array or hash element) the variable is assigned a reference to a new anony- mous filehandle,
    In any case IMHO you should either do some checks or rely on Perl's automagic ARGV.

    Update: I realized now that you were talking about somebody else's code and you were concerned about the lack of checks yourself in the first place. Also, I removed the unrelevant portions of the quote.

    Update2: I knew the answer but in a hurry I quoted the wrong portion of perldoc -f open. There's a lesson in this: never rely too much on searching for 'anonymous'...

      "FILEHANDLE" is the first argument but this thread is about the 3rd argument, so I don't see how the documentation you quote has anything to do with what is being discussed.

      Update: But we aren't using "+<" nor "+>" so that section doesn't apply either.

      - tye        

        Indeed. I quoted the wrong portion of perldoc -f open. My fault. I have updated it now!
        Update: But we aren't using "+<" nor "+>" so that section doesn't apply either.
        Actually it is not documented (so I was incorrect in another post that it is "perfectly" documented), but it applies. Indeed I found out that it even works with a '<' mode. See my own I've been bit in the neck by open().
Re: 3-arg open() does not give warnings!?
by Transient (Hermit) on Jul 15, 2005 at 16:31 UTC
    I couldn't get this out of my head so I looked at the Perl C code. While it was hard to follow until I scanned the .h's for pre-defs.. I think I have the jist of it: (Please note this is 5.8.7) This is my first time delving into the perl C-source. If I've said anything that's blatantly wrong, I apologize, and please do correct me in the thread. I just wanted to research this and share my psuedo-findings with the rest of the monastery.
      The last comment inside your "Readmore" section was:
      it seems that it would be the same whether or not there was a '+' before the '<' or '>'

      That's the problem! The man page for open only talks about using "+>" or "+<" as the "special 3-arg case with the third arg being undef" in order to establish read/write access to an anonymous temp file. This makes sense, because the temp file is going to vanish as soon as the file handle goes out of scope, and only the portion of the script where the handle is in scope can see that file, and write and then read data there. That's cool.

      The man page does not describe any sort of "special 3-arg case with the third arg being undef" when there is just a bare "<" or ">" as the 2nd arg -- because this sort of usage makes no sense: why open an anonymous temporary file (non-existent outside the scope of the file handle, unknowable and inaccessible to any other process) for only read access, or only write access??? That's pointless!

      So the fact that perl seems to be treating "+>" the same as ">" in this case (and likewise for "<") looks very much like A BUG.

      Your discussion of the perl source code was a fair bit over my head (if you made any mistakes, I wouldn't know), but I thank you for it, just the same.

Re: 3-arg open() does not give warnings!?
by Transient (Hermit) on Jul 15, 2005 at 13:57 UTC
    From open:

    As a special case the 3 arg form with a read/write mode and the third argument being undef:

     open(TMP, "+>", undef) or die ...

    opens a filehandle to an anonymous temporary file. Also using "+<" works for symmetry, but you really should consider writing something to the temporary file first. You will need to seek() to do the reading.


    perl -le 'print defined($ARGV[0])?"defined":"undefined"'
    prints "undefined"

    Update: Sorry, posted this just as blazar updated Re: 3-arg open() does not give warnings!? with the right quote! =D
Re: 3-arg open() does not give warnings!?
by Random_Walk (Prior) on Jul 15, 2005 at 13:02 UTC

    I get the same behaviour on AIX ...

    =>perl -le'open I, "<", $ARGV[0] or die "$!"; print while <I>;print "d +one"' done =>perl -le'open I, "<$ARGV[0]" or die "$!"; print while <I>;print "don +e"' A file or directory in the path name does not exist. at -e line 1. => perl -v This is perl, v5.8.0 built for aix-thread-multi
    Both versions work fine if I pass it a filename.

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!
Re: 3-arg open() does not give warnings!?
by jhourcle (Prior) on Jul 15, 2005 at 13:51 UTC

    Your example 'bad' item, if ARGV[0] is undefined, would be the same as:

    open ( O, '>', undef ) or die $!;

    Because you're stringifying an undefined value in your two arg case, it would actually be closer to the three arg:

    my $file = undef; open ( O, '>', "$file" ) or die $!;

    I agree it's a problem... I just didn't think that the two tests were similar. (and I have no idea how open does the test for how many args it was passed, so it's possible that this is an odd edge case that doesn't get processed at all...)

Re: 3-arg open() does not give warnings!?
by sh1tn (Priest) on Jul 15, 2005 at 13:24 UTC
    Maybe operator priority:
    open FH, ">", $ARGV[0] || die "'OR' operator should be '||'\n";


        What I mean is:
        open FH, ">", ( $ARGV[0] || die "...");
        Of course this is not a solution, because this does not check errors from open function but it works fine for me.


Re: 3-arg open() does not give warnings!?
by socketdave (Curate) on Jul 15, 2005 at 13:15 UTC
    I see the same behavior on 5.8.4 on Linux.
Re: 3-arg open() does not give warnings!?
by rev_1318 (Chaplain) on Jul 15, 2005 at 13:22 UTC
    Same with perl 5.8.5 on Linux... I would call this a bug!

    Paul