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

hi monks

I'm trying to check if a file exists, and if it does, increment the name and create a new one.

So if the file 07141998.html exists, I want to create 07141998_1.html

(of course I need to check if _that_ exists first...)

Here's how I do it:

$name = ..... # whatever
if (-e $name) {
for (my $i = 1; -e ($name = $name."_$i"); $i++) {}; # get unique name
}

I took the above code from a site...so i want to know how does the "e" works in the above code....can anybody help me understand it

Thanks
lax

Replies are listed 'Best First'.
Re: unique filename
by Fletch (Bishop) on Jul 21, 2006 at 13:04 UTC

    All of these solutions using -e are introducing a race condition(*) into your code. If you can guarantee there's only ever going to be a single instance of this running at any given time, you might decide that's OK and live dangerously.

    If you can't (or you're sufficiently paranoid to do it correctly the first time :), you need to look at using sysopen and the O_EXCL flag. You keep trying to open filenames until one succeeds, then you go on and write into it. See also perlopentut for examples using sysopen in this way.

    (*) The race condition is that your test for the file's existence and the opening of the filename aren't a single, atomic action. It's entirely possible that two separate processes could check for the existence of the same filename simultaneously and both think they both can write to the same "unique" filename. Using sysopen and O_EXCL makes the test-and-open a single action which either succeeds or fails as one. Many security holes can be traced back to race conditions; do it right the first time and avoid them to begin with.

Re: unique filename
by neversaint (Deacon) on Jul 21, 2006 at 07:07 UTC
    I think it is pretty straight forward:
    if (-e $name) {
    basically check if the file exists or not. And you know about this already I suppose.
    -e ($name = $name."_$i")
    in the for loop basically loop over the file. It has the same meaning as if you do this:
    my $name = $name."_$i"; # input file name open ( INF, '<', $name ) or croak "$0 : failed to open output file $name : $!\n"; while(<INF>) { # Do something } close ( INF ); # close input file
    Finally, read -X.



    ---
    neversaint and everlastingly indebted.......
Re: unique filename
by wfsp (Abbot) on Jul 21, 2006 at 08:01 UTC
    Hi lax

    Have a look at Auto-increment and Auto-decrement

    In particular: "The auto-increment operator has a little extra builtin magic to it."

    Combined with neversaint's suggestion you may be able to dispense with the $i altogether.

    As Dolly Parton famously said about looking at the docs: "That's what they're for!". Although she might not have been talking about the docs. :-)

    Update

    See my reply to Skeeve below.

      Hi wfsp!

      Can you please give an example how to get rid of the $i here? I always wanted that but never found a way to get filenames incremented without a temporary variable.

      perl -e '$fname= "testname_1";print "$fname\n",++$fname,"\n"'
      prints
      testane_1
      1
      Not a useable result...

      s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
      +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e

        The "magic" alphabetic increment doesn't work when there is a non (Update: ASCII it appears ) alphanumeric character in there such as the '_' in this case.

        /J\

        Skeeve

        I should have tested before I posted :-)

        The 'magic' can be useful but with caveats. The following snippet shows when it does work (the first three) and when it doesn't (the final three).

        #!/usr/bin/perl use strict; use warnings; my @array = qw(a123 abc abc1 123a 123_1 abc_1); for my $element (@array){ print "before: $element\n"; $element++; print "after: $element\n"; print "\n"; } __DATA__ output (with comments) # these "do what you want" before: a123 after: a124 before: abc after: abd before: abc1 after: abc2 # and these don't :-( # if the string starts with a number # Perl treats it as number before: 123a after: 124 # the _ always breaks the magic before: 123_1 after: 124 # not at all sure what's happening here! before: abc_1 after: 1
Re: unique filename
by Skeeve (Parson) on Jul 21, 2006 at 08:04 UTC
    Just as a side node and because TMTOWTDI, I do such tests like this:
    $name = ..... # whatever my $i= ''; --$i while (-e $name . $i); $name.= $i;

    Of course this will give you -1 instead of _1.

    Did you notice that your "_1" is appended to the ".html"? You don't get 07141998_1.html but 07141998.html_1. For demonstration purposes, mine isn't better here.

    A fix could be TMTOWTDI:

    my $check= $name; $check=~ s#(\.[^./]*)$##; my $ext= $1 || ''; my $i= ''; --$i while (-e $check . $i . $ext); $name= $check . $i . $ext;

    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
    +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e