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

# get a temp file name do { $name = tmpnam() } until sysopen(FH, $name, O_RDWR|O_CREAT|O_EXCL);
am I wrong in thinking that the above code is deprecated?

Replies are listed 'Best First'.
Re: do until sysopen()
by blakem (Monsignor) on Oct 22, 2001 at 11:22 UTC
    You can also use File::Temp, which can give you back an open filehandle and a filename. (thus avoiding various race conditions)
    use File::Temp qw(tempfile); my ($fh, $filename) = tempfile( DIR => $tmpdir );

    -Blake

Re: do until sysopen()
by Zaxo (Archbishop) on Oct 22, 2001 at 11:14 UTC

    tmpnam is not a builtin perl function, but is available with use POSIX qw(tmpnam);. You seem to use more control struct than is needed, as if you expect the system to need to retry a few times before giving you a file. It would be best to simply call tmpnam() once in sysopen(FH, POSIX::tmpnam(), O_RDWR|O_CREAT|O_EXCL) or die $!;

    You might like to try IO::File:

    use IO::File; my $fh = IO::File->new_tmpfile();
    and you never need to know its name.

    Update: Added import list for POSIX.

    Update2: Scratched blunder, here is something that gets by tye's astute objection to your idiom:

    use POSIX; my ($tmpfh, $name); do { $name = POSIX::tmpnam() } until sysopen( $tmpfh, $name, O_RDWR|O_CREAT|O_EXCL) or # if error, then $! !~ m/File exists/ # try again if bad name && die $!; # else die
    This depends strongly on lazy evaluation of logical operators.

    After Compline,
    Zaxo

      It would be best to simply call tmpnam() once

      No, the point is that tmpnam() can give you the name of a file that doesn't exist and then, by the time you get a chance to call sysopen, someone else has created a file with that name. This is called a race condition.

      Specifying O_EXCL to sysopen means that it will fail if the race condition happens so that you can retry, which means requesting a new file name.

      But I wouldn't use the original code because, for one thing, it will just loop forever if sysopen is failing for a reason other than "file already exists". So I'd go with File::Temp (which isn't included with Perl [update: prior to version 5.6.1], unfortunately). Despite there being lots of methods avaiable for creating temporary files in Perl, it appears that only File::Temp "gets things right" and gets rid of the race conditions in a portable manner. Though I haven't investigated this thoroughly so I'd be happy to be proved wrong on that. (:

              - tye (but my friends call me "Tye")