http://qs321.pair.com?node_id=691281

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

Want to be a Perl contributor? It's easy. Just fix this FAQ answer. Update: An by update, I mean rewrite it, not tell me how to rewrite it. :)

perlfaq5 has an answer for "How can I translate tildes (~) in a filename?". Looking at the code in the answer, I know it must break in a lot of places since it relies either on getpwnam or environment variables. Who can come up with a good answer that is more robust? I'm especially interested in any module-fu that can be added. You don't have to necessarily keep any of the existing answer. If you replace the answer, you get your name listed right next to it. :)

You can post your answer here or to the mailing list in perlfaq.

Here's the source (although you can get at the svn repository too by looking at the instructions in perlfaq:

=head2 How can I translate tildes (~) in a filename? X<tilde> X<tilde expansion> Use the E<lt>E<gt> (C<glob()>) operator, documented in L<perlfunc>. Versions of Perl older than 5.6 require that you have a shell installed that groks tildes. Later versions of Perl have this feature built in. The C<File::KGlob> module (available from CPAN) gives more portable glob functionality. Within Perl, you may use this directly: $filename =~ s{ ^ ~ # find a leading tilde ( # save this in $1 [^/] # a non-slash character * # repeated 0 or more times (0 means me) ) }{ $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} ) }ex;
--
brian d foy <brian@stonehenge.com>
Subscribe to The Perl Review

Replies are listed 'Best First'.
Re: Improve perlfaq5: How can I translate tildes (~) in a filename?
by halley (Prior) on Jun 10, 2008 at 18:47 UTC
    I'm not sure what the actual beef might be with that solution. Here is an explanatory paragraph to introduce the FAQ, which may be all it needs.
    On systems which follow Unix shell conventions, a user may supply a pathname with the tilde (~) character to refer to the user's home directory (e.g., <c>~/file</c>), or another user's home directory (e.g., <c>~user/file</c>). This works in many Unix shells, but often does not work in scripts or applications by default. If your script would like to support this convenient but optional notation, then the built-in <c>getpwnam()</c> function and <c>%ENV</c> hash are the best places to refer, or use the newer globbing features that support them automatically.
    On non-Unix systems, it might be broken. On non-Unix systems, though, the users are less likely to want to use Unix-isms like shell notations that scan /etc/passwd for data. Wrap the whole thing in a $^O if you like.

    --
    [ e d @ h a l l e y . c c ]

Re: Improve perlfaq5: How can I translate tildes (~) in a filename?
by Limbic~Region (Chancellor) on Jun 10, 2008 at 19:43 UTC
    brian_d_foy,

    Presumably the edge cases you described are solved in one or more of these modules. I haven't looked myself, but you did ask for module fu. The first one claims to work on any platform for instance.

    Cheers - L~R

    Update: Added more modules as my search fu improved
Re: Improve perlfaq5: How can I translate tildes (~) in a filename?
by adamk (Chaplain) on Jun 11, 2008 at 01:51 UTC
    Something like this would probably do it (I haven't actually tested it)
    require File::HomeDir; $filename =~ s/^~(\w+)/File::HomeDir->users_home("$1")/e; $filename =~ s/^~/File::HomeDir->my_home/e;
      Works fine for me:
      $ cat 691281.pl use strict; use warnings; use File::HomeDir; use Test::More; plan tests => 4; sub rep_tilde { my $filename = shift; $filename =~ s/^~(\w+)/File::HomeDir->users_home("$1")/e; $filename =~ s/^~/File::HomeDir->my_home/e; return $filename; } is(rep_tilde("~"), "/home/foo", "expect ~ -> /home/foo"); is(rep_tilde("~/"), "/home/foo/", "expect ~/ -> /home/foo/"); is(rep_tilde("~/.feeds"), "/home/foo/.feeds", "expect ~/.feeds -> /home/foo/.feeds"); is( rep_tilde("~/test/perl/perlmonks/691281/691281.pl"), "/home/foo/test/perl/perlmonks/691281/691281.pl", "expect ~/test/perl/perlmonks/691281/691281.pl " . "-> /home/foo/test/perl/perlmonks/691281/691281.pl" ); __END__ $ prove 691281.pl 691281....ok All tests successful. Files=1, Tests=4, 0 wallclock secs ( 0.05 cusr + 0.00 csys = 0.05 C +PU)
      --
      No matter how great and destructive your problems may seem now, remember, you've probably only seen the tip of them. [1]
Re: Improve perlfaq5: How can I translate tildes (~) in a filename?
by pc88mxer (Vicar) on Jun 10, 2008 at 19:05 UTC
    What's interesting is that the logic used in bsd_glob.c seems to be the reverse: first $HOME is checked and then getpwuid is called.