Brad.Walker has asked for the wisdom of the Perl Monks concerning the following question:

I have a question about how to read the following Perl code:

my $limit = 99999; my $md; # Creates unique tmpfile do { $tmpname = int(rand($limit)); $md = "$TMPDIR/runitout_$tmpname"; } until (! -f "$md");
Specifically I'm interested in how to read the until statement.

Any help is much appreciated.

-brad w.

Replies are listed 'Best First'.
Re: how do I read this Perl code..
by davidrw (Prior) on Dec 13, 2006 at 15:42 UTC
    What this snippet appears to be doing is to construct a random filename, and do so until it finds a filename that does not exist. And the name is of the form <TMPDIR>/runitout_NNNNN
    The "until" reads as "until we have a file that does not exist", i.e., until a "free" filename.
    For more information on the -f and others, see -X

    Also note that a more robust general approach would be to use the File::Temp module.
Re: how do I read this Perl code..
by marto (Cardinal) on Dec 13, 2006 at 15:46 UTC
    Hi Brad,

    within the do loop the $tempname variable is assigned a randomly chosen value between zero and $limit, which we can see is 99999. $md is then assigned the value of $TMPDIR (not listed in the code you provided) pluse the sring "/runitout_" and the value of $tempname. This will happen until no(the !) file exists (-f) for the value of $md shown in until (! -f "$md"); at the end of the do construct. It there are any parts you dont understand check out perldoc and the Tutorials section of this site. Perhaps the module File::Temp may also be of interest to you.

    Comment version of your code:
    my $limit = 99999; my $md; # Creates unique tmpfile do { #do the following $tmpname = int(rand($limit)); #$tmpname = convert t +o integer random number between 0 and $limit (99999) $md = "$TMPDIR/runitout_$tmpname"; #$md = "$TMPDIR/run +itout_$tmpname" concatinated values of $TMPDIR (not listed) the strin +g "/runitout_" and the value of $tmpname } until (! -f "$md"); #until file $md does + not exist

    Hope this helps.

    Martin

    Update: Fixed typo, later added a commented version of the user provided script
Re: how do I read this Perl code..
by liverpole (Monsignor) on Dec 13, 2006 at 16:03 UTC
    Hi Brad.Walker,

    Just a note about style and readability (though I agree that File::Temp sounds like a good idea) ...

    Since unless is discouraged in cases where it's potentially confusing (instead you can use while (not ...)), and since you already have a negative in the command (the "!" in (! -f "$md")), I would strongly prefer writing it as:

    do { $tmpname = int(rand($limit)); $md = "$TMPDIR/runitout_$tmpname"; } while (-f $md);

    Note, too, that you don't need quotation marks around $md.


    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
Re: how do I read this Perl code..
by MidLifeXis (Monsignor) on Dec 13, 2006 at 19:28 UTC

    Since you have been given the " use File::Temp" speech, but not why, I will try to fill it in...

    You have a race condition: application_1 and application_2, both using this code snippit, could come up with the same file name and both apps could attempt to use the temporary file. In the past, this code has led to root / administrator level exploits of systems.

    File::Temp is yet another tool to help avoid this type of race condition.

    --MidLifeXis

Re: how do I read this Perl code..
by throop (Chaplain) on Dec 13, 2006 at 17:40 UTC
    Following on the other, able answers...

    Wouldn't the -e test be better than -f? That is, if TMPDIR/runitout_XXXXXX exists as a directory, won't -f return false?

    throop

Re: how do I read this Perl code..
by cephas (Pilgrim) on Dec 13, 2006 at 21:14 UTC
    I'll skip the File::Temp speech, everyone else has mentioned. However there is probably a bug in the larger picture of the code here. First, as someone mentioned, there's nothing to keep a directory from existing by that name, the -f return false. The other is that now that you've got a filename that isn't use, what are you doing with it? There's nothing that guarantees it doesn't get used by another process between the time that you generate it and the time you do something with it. If you are wanting to create a tmp file (without using File::Temp for some reason), then try:
    #!/usr/bin/perl use strict; use Fcntl; my $TMPDIR = "/tmp"; my $limit = 99999; my $md; do { my $tmpname = int(rand($limit)); $md = "$TMPDIR/runitout_$tmpname"; } until(sysopen(my $fd, $md, O_CREAT|O_EXCL));

    This will loop until it can create the file in question, and the O_EXCL means that the create will fail if that file is already in existence.