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

Hi, I'm currently working on the following script:

use strict; use warnings; my $usage = "Usage: $0 <infile.txt>\n"; my $infile = shift or die $usage; use File::Basename; my $DIR = dirname($infile); my $outfile = $DIR . "/Results.txt" or die $usage; open (my $data, "<", $infile) or die "There was a problem opening: $!" +; my @primers = <$data>; close $data; chomp @primers; use Algorithm::Combinatorics qw(combinations); my $strings = \@primers; my $iter = combinations($strings, 2); open(my $fh, '>', $outfile); while (my $c = $iter->next) { print $fh @$c, "\n"; } print ("Finished. The results are located at $outfile\n\n");

I was wondering if there was a simple method for allowing outfile to be sequentially numbered if an existing file is found i.e. Results.txt, Results1.txt, Results2.txt? I've seen a few methods around however they do seem quite long and i'm curious to see if there's an available module or easier way to do it! Thanks!

  • Comment on Sequentially numbering output files rather than overwriting an existing file
  • Download Code

Replies are listed 'Best First'.
Re: Sequentially numbering output files rather than overwriting an existing file
by kcott (Archbishop) on Jan 08, 2014 at 15:34 UTC

    G'day TJCooper,

    Here's one way you might go about this:

    #!/usr/bin/env perl -l use strict; use warnings; use autodie; my $highest = 0; my $re = qr{pm_1069813_results(\d+)\.txt}; opendir my $dh, '.'; map { /$re/ and $1 > $highest and $highest = $1 } readdir $dh; closedir $dh; my $next_file = 'pm_1069813_results' . ++$highest . '.txt'; print "Next file: $next_file";

    Output:

    Next file: pm_1069813_results4.txt

    Current files:

    $ ls -1 pm_1069813_results*.txt pm_1069813_results1.txt pm_1069813_results2.txt pm_1069813_results3.txt

    -- Ken

      Interesting way of going about it. Thank you!
Re: Sequentially numbering output files rather than overwriting an existing file
by educated_foo (Vicar) on Jan 08, 2014 at 17:05 UTC
    For the first unused "$name$n.txt" file:
    if (-f "$name.txt") { $n=1; $n++ while -f "$name$n.txt"; }
    For one greater than the highest "$name$n.txt" file, something like kcott's solution below works.
      For more visually pleasing output:
      if (-f "$name.txt") { $n=1; my $fn = sprintf "%s-%05d\.txt", $name, $n; $n++ while -f $fn; }
Re: Sequentially numbering output files rather than overwriting an existing file
by duelafn (Parson) on Jan 09, 2014 at 00:46 UTC

    If you don't want to risk races, use sysopen and loop until you can create the file yourself:

    #!/usr/bin/perl -w use strict; use warnings; use 5.010; use Fcntl qw/ O_CREAT O_EXCL O_WRONLY /; my $fh = open_next( "Results", ".txt" ); print $fh "Hello!\n"; sub open_next { my ($prefix, $suffix) = @_; my $number = 0; my $FH; until (sysopen($FH, ($prefix . ($number || "") .$suffix), O_WRONLY +|O_EXCL|O_CREAT)) { $number++; } return $FH; }

    Good Day,
        Dean

Re: Sequentially numbering output files rather than overwriting an existing file
by Laurent_R (Canon) on Jan 08, 2014 at 23:27 UTC

    You can work on VMS: the OS automatically assigns version numbers (starting with 1) to files that you create. If you create a "foo.txt" file, VMS actually creates "foo.txt;1". When you modify this file, a new version, "foo.txt;2" will be created. ;-)

    More seriously, I had to create recently directories with sequence numbers, say something like foo1, foo2, foo3, etc. I did something similar to this (from sheer memory, I did not test the version posted here):

    my $root_name = "foo"; my $next_number = (sort {$b <=> $a} map {/(\d+)$/; $1} glob("${root_na +me}*"))[0] + 1; my $next_name = "$root_name$next_number"; # ...
    Perhaps slightly less efficient than Ken's code if you have hundreds of thousands of directory entries (because a full sort if overkill in this context), but my sequence numbers had to be limited by a smaller upper limit anyway, but using sort made the coding easier.