Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

TIMTOWTDI Challenge: Create a filename

by Tanktalus (Canon)
on Jan 08, 2009 at 20:31 UTC ( #735007=perlmeditation: print w/ replies, xml ) Need Help??

In this, the second in a series of challenges (see the first such challenge), the goal is to explore the language in ways to create a filename. Inspired by a brief conversation on the CB where thezip suggested the mundane "sprintf is your friend," I'm looking for any and all ways to create a filename.

As in the previous challenge, the wording is deliberately vague. You can take this to mean anything you want, as long as the end result is the name of a file. The file may exist, or it may not exist, or its existence may be indeterminate. The choice is up to you.

Entries need not be serious - they can be exploratory (as davido pointed out last time, exporing the corners of the language is sometimes valuable), but pros and cons should be listed. Sometimes an off-beat approach is just what is needed, and knowing the pros and cons of an approach is vital in such evaluation. And, in the context of this challenge, it proves you know what you're doing rather than just copying and pasting it :-)

As to some examples:

# thezip's method: $fn = sprintf "%s.%04d-%02d-%02d-%02d%02d%02d.ext", $base_name, (localtime)[5,4,3,2,1,0];
Straight-forward, though there's a bit more work to get natural numbers for year and month. strftime would probably be better here.
# my method (from CB): $fn = ''; { open my $fh, '>', \$fn; print $fh $base_name, '.'; print $fh strftime("%F-%T"); }
pro: we're preparing this for open, so what could be more natural than using open for that? :-)
con: um, don't ever do this?

If you have some standard tools, even if wacky, esoteric, domain-specific, please share them. Or if you just are going for bonus points for obtuseness, please do. I managed to learn a lot from last time (including IO::All, the "cat $file |" trick for too-large-for-perl files, using Win32::OLE on Windows, though not necessarily in this order of usefulness ;-)), and I noticed others did as well, so don't be afraid to add your trick - you won't know who will find it helpful, even as an eye-opener, unless you do.

Comment on TIMTOWTDI Challenge: Create a filename
Select or Download Code
Re: TIMTOWTDI Challenge: Create a filename
by zentara (Archbishop) on Jan 08, 2009 at 20:52 UTC
    Why not go with straight unix time, so sorting would be easy.
    #!/usr/bin/perl $fname = time.'.'.('0' x (14 - length(int(rand(1e14))))) . int(rand(1e +14)); print "$fname\n"; open (FILE,"> $fname"); close FILE;
    Very low name collision rate. :-)

    I'm not really a human, but I play one on earth Remember How Lucky You Are
Re: TIMTOWTDI Challenge: Create a filename
by moritz (Cardinal) on Jan 08, 2009 at 21:05 UTC
    For creating not-yet-existing filenames, File::Temp is surely the weapon of choice if it has to be robust.

    A typical usage is just

    use File::Temp qw(tempfile); my ($handle, $name) = tempfile();

    That protects you from race conditions, so for example if you have a test suite that uses temporary files, and somebody runs them in parallel, it doesn't all blow up.

    The downside is the names aren't pretty (although you can provide a template to make it start pretty at least).

Re: TIMTOWTDI Challenge: Create a filename
by jeffa (Chancellor) on Jan 08, 2009 at 21:20 UTC

    Once we have the filename -- how do we create it? I think this way is a pretty awesome yet stupid way of doing just that. It's not even platform independent!

    use File::Temp qw(tempfile); my (undef,$file) = tempfile( DIR => '.' ); `echo "#!/bin/touch $file" > tmp.sh`; chmod 0755, 'tmp.sh'; system './tmp.sh';

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    

      Hey!

      % which touch /usr/bin/touch

      Portability counts! You should make it more robust. Maybe with env...

      `echo "#!/usr/bin/env touch $file" > tmp.sh`;

      Of course, that's slower at runtime. Extra forks and all. Maybe precalculate it...

      `echo "#!\$(which touch) $file" > tmp.sh`;

      But really, sh is pretty weak. And we've already got perl anyway, right? So why not use it to its fullest incapacity?

      `echo "#!/usr/bin/env perl -e 'system \"\$(which touch) $file\"'" > tm +p.pl`; system './tmp.pl';

      Of course, that's getting pretty silly. And tedious. Obviously a little metaprogramming is called for to generate those expressions...

Re: TIMTOWTDI Challenge: Create a filename
by fullermd (Curate) on Jan 09, 2009 at 03:27 UTC
    As in the previous challenge, the wording is deliberately vague. You can take this to mean anything you want, as long as the end result is the name of a file. The file may exist, or it may not exist, or its existence may be indeterminate. The choice is up to you.

    In the spirit of stretching the bounds of the question...

    The other entries all seem to assume the purpose is to get a file for temporary purposes. But that's never stated. So the simplest way to get a file would be:

    $file = $0;

    Of course, that doesn't guarantee you a file either:

    % perl -e 'print "$0\n"' -e

    So how do you guarantee that you get a file? Well... I don't think you can. It's at least theoretically possible that your filesystem has no files in it. Or even that you don't have a filesystem.

    But then, it doesn't have to exist. The question even says its existence may be indeterminate, so it doesn't even have to be accessible at all.

    $file = "/foo";
Re: TIMTOWTDI Challenge: Create a filename
by xdg (Monsignor) on Jan 09, 2009 at 05:13 UTC

    Assuming a quick-and-dirty temporary filename is desired:

    my $filename = int rand 2**31;

    Or pick a large random number of your choice. Plus if you need to generate the *same* temporary filenames on successive runs, you can set the seed for rand() ahead of time.

    Similar in nature, but random alphanumerics, not unlike what File::Temp does internally:

    my @chars = ('a' .. 'z', 'A' .. 'Z'); my $filename = join("", map { $chars[int rand(0+@chars)] } 0 .. 7);

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      To fully exploit the marvelous utility of the unix file system naming conventions, how about this?

      my $max_num = 255; my @chars = ('a' .. 'z', 'A' .. 'Z',0 .. 9, '_'); my $filename = join("", map { $chars[int rand(0+@chars)] } 1 .. $max_n +um);

      I don't have the energy right now, but a further helpful revision would be filling in all of the characters Unix allows in filenames. Oh, wait. That would be all of them except null. The mind boggles ;-)

      for(split(" ","tsuJ rehtonA lreP rekcaH")){print reverse . " "}print "\b.\n";
Re: TIMTOWTDI Challenge: Create a filename
by ysth (Canon) on Jan 09, 2009 at 05:39 UTC
    I've come up with a marvelously efficient way...so far I've only tested with short filenames, though.
    sub rand_filename { my ($base_len, $ext_len, $charset) = @_; my ($filename, $count); ++$count*rand() < 1 and $filename = $_ while $_ = glob sprintf q!% +s!x$base_len.".".q!%s!x$ext_len, map { "{".join(",",split //, $charse +t)."}" } 1..($base_len + $ext_len); $filename } print rand_filename( 2, 1, join("","a".."z") );
Re: TIMTOWTDI Challenge: Create a filename
by JavaFan (Canon) on Jan 09, 2009 at 09:27 UTC
    I prefer short programs. And short filenames. And deterministic approaches. So, my entry:
    say"";
    This creates a filename consisting of a newline. Under Unix, annoying, but in most Unix file systems, valid.
Re: TIMTOWTDI Challenge: Create a filename
by grinder (Bishop) on Jan 09, 2009 at 10:25 UTC

    I tend to go with a variant of thezip's method, but I flow the results of the localtime slice through a coderef to make the month and years readable to an ordinary human. So it goes something like this:

    my $fn = sub { sprintf "$base_name-%04d-%02d-%02d-%02d%02d%02d.ext", $_[5] + 1900, $_[4]+1, reverse(@_[0..3]) }->(localtime);

    Like thezip, I use a YYYY-MM-DD format so that files sort nicely in a directory.

    • another intruder with the mooring in the heart of the Perl

      grinder has the right idea, keeping in human readable in sort order, that's what I do, but I also toss in $$ (process id) because I have many processes making temp files, and do have collisions.
Re: TIMTOWTDI Challenge: Create a filename
by setebos (Beadle) on Jan 09, 2009 at 17:32 UTC
    If the aim is to create a temporary file name (quite slow method):

    use Time::HiRes qw(gettimeofday); my $rand = \&gettimeofday; my $temp_file_name = sub{ int(rand($rand->())) }; $temp_file_name = sub{ local $.; $..= $temp_file_name->() for 1..5; return $.; }->();
Re: TIMTOWTDI Challenge: Create a filename
by liverpole (Monsignor) on Jan 09, 2009 at 19:15 UTC
    I like the idea by setebos of using gettimeofday for high-granularity time.  But I'd prefer a one-to-one mapping between timeofday and the filename, so, using the transliteration operator 'y', along with the most common letters (but including all of the vowels, even 'y'):
    use strict; use warnings; use Time::HiRes qw/gettimeofday/; while (1) { my $fname = create_filename_from_current_time(); print "Filename is '$fname'\n"; } sub create_filename_from_current_time { (my $fname = gettimeofday) =~ y/0-9/etaonirsuy/; return $fname; }
    This produces output of the sort:
    Filename is 'taotiaueta.retry' Filename is 'taotiaueta.retso' Filename is 'taotiaueta.retsu' Filename is 'taotiaueta.retuo' Filename is 'taotiaueta.retuu' Filename is 'taotiaueta.retya' Filename is 'taotiaueta.retys' Filename is 'taotiaueta.reaea' Filename is 'taotiaueta.reaes' Filename is 'taotiaueta.reatt' Filename is 'taotiaueta.reatr' Filename is 'taotiaueta.reaat' Filename is 'taotiaueta.reaai' Filename is 'taotiaueta.reao'
    I like that the "extension" of the first filename in the list is coincidentally a real word!

    s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/
      Nice. If one were to make that
      y/0-9/abcdefghij/;
      the output would be human readable in sort order as suggested by dwhite20899 above.
      --
      No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]
Re: TIMTOWTDI Challenge: Create a filename
by stvn (Monsignor) on Jan 09, 2009 at 21:33 UTC
    Perl is the syntax, CPAN is the language.

    I actually wrote Path::Class::Versioned for just this type of problem.

    -stvn

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://735007]
Approved by toolic
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (13)
As of 2014-07-25 16:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (173 votes), past polls