#!/usr/bin/perl -w # safely create uniquely-named files. # # Example: create ten empty .ps files # zsh% repeat 10 do timefile ps; done use strict; use Time::HiRes qw( gettimeofday usleep ); use Fcntl qw(:DEFAULT :flock); umask(022); sub newfile(;$;$); sub randbetween ($$); my $exten = shift(@ARGV) || 'txt'; my $file; $file = newfile(".", $exten); print "$file\n"; exit(0); sub newfile (;$;$) { my ($dir) = shift (@_) || "."; my ($exten) = shift (@_) || "txt"; unless (-d "$dir") { warn "newfile: $dir: not a directory\n"; return ""; } my ($nap) = randbetween(1000, 10000); my ($reps) = 3; my ($sec, $usec, $nfile, $status); while (--$reps > 0) { ($sec, $usec) = gettimeofday; # we want milliseconds. $usec = sprintf("%3.3d", int($usec / 1000)); $nfile = "$dir/$sec.$usec.$exten"; if (sysopen(FH, "$nfile", O_RDWR | O_CREAT | O_EXCL)) { if (flock(FH, LOCK_EX)) { seek(FH, 0, 0) and truncate(FH, 0); close(FH) or die "can't close $nfile: $!"; last if -f $nfile; } } usleep($nap); } # if $reps > 0, we successfully created a new file. $nfile = '' unless $reps; return $nfile; } # create random number between two integers. sub randbetween ($$) { my ($min, $max) = @_; # Assumes that the two arguments are integers themselves! return $min if $min == $max; ($min, $max) = ($max, $min) if $min > $max; return $min + int rand(1 + $max - $min); }