Expanding Tildes in Filenames (Perl Cookbook, 2nd Edition)

## 7.3. Expanding Tildes in Filenames

### 7.3.1. Problem

You want to open filenames like ~username/blah or ~/.mailrc, but `open` doesn't interpret the tilde to mean a home directory.

### 7.3.2. Solution

Either use the `glob` function:

>     open(FH, glob("~joebob/somefile")) || die "Couldn't open file: $!";

or expand the filename manually with a substitution:

>     $filename =~ s{ ^ ~ ( [^/]* ) }
>                   { $1
>                         ? (getpwnam($1))[7]
>                         : ( $ENV{HOME} || $ENV{LOGDIR}
>                              || (getpwuid($<))[7]
>                            )
>     }ex;

### 7.3.3. Discussion

There is a useful convention, begun with the Unix csh shell and propagated widely by web addresses of the form http://www.example.com/~user/, that ~ in a filename represents a user's home directory. Thus:

>         ~              # current user's home directory
>         ~/blah         # file blah in current user's home directory
>         ~user          # a particular user's home directory
>         ~user/blah     # file blah in a particular user's home directory

Unfortunately, Perl's `open` function does not expand wildcards, including tildes. As of the v5.6 release, Perl internally uses the File::Glob module when you use the `glob` operator. So all you need to do is `glob` the result first.

>     open(MAILRC, "<", "~/.mailrc")           # WRONG: tilde is a shell thing
>         or die "can't open ~/.mailrc: $!";

>     open(MAILRC, "<", glob("~/.mailrc"))     # so expand tilde first
>         or die "can't open ~/.mailrc: $!";

The alternative solution, the substitution, uses `/e` to evaluate the replacement as Perl code. If a username follows the tilde, it's stored in `$1`, which `getpwnam` uses to extract the user's home directory out of the return list. This directory becomes the replacement string. If the tilde was not followed by a username, substitute in either the current `HOME` environment variable or the `LOGDIR` one. If neither of those is valid, look up the effective user ID's home directory.

You could spell `glob('~gnat')` as `<~gnat>`, but that would look too much like a read from a filehandle, so don't do that.

### 7.3.4. See Also

The `glob` and `getpwnam` functions in perlfunc(1) and Chapter 29 of Programming Perl; your system's getpwnam(2) manpage; Recipe 9.6

Copyright © 2003 O'Reilly & Associates. All rights reserved.