Splitting a Filename into Its Component Parts (Perl Cookbook, 2nd Edition)

## 9.10. Splitting a Filename into Its Component Parts

### 9.10.1. Problem

You want to extract a filename, its enclosing directory, or the extension(s) from a string that contains a full pathname.

### 9.10.2. Solution

Use routines from the standard File::Basename module.

>     use File::Basename;

>     $base = basename($path);
>     $dir  = dirname($path);
>     ($base, $dir, $ext) = fileparse($path);

### 9.10.3. Discussion

The standard File::Basename module contains routines to split up a filename. `dirname` and `basename` supply the directory and filename portions, respectively:

>     $path = "/usr/lib/libc.a";
>     $file = basename($path);
>     $dir  = dirname($path);

>     print "dir is $dir, file is $file\n";
>     # dir is /usr/lib, file is libc.a

The `fileparse` function can extract the extension. Pass `fileparse` the path to decipher and a regular expression that matches the extension. You must supply a pattern because an extension isn't necessarily dot-separated. Consider "`.tar.gz`": is the extension "`.tar`", "`.gz`", or "`.tar.gz`"? By specifying the pattern, you control which you get.

>     $path = "/usr/lib/libc.a";
>     ($name,$dir,$ext) = fileparse($path,'\..*');

>     print "dir is $dir, name is $name, extension is $ext\n";
>     # dir is /usr/lib/, name is libc, extension is .a

By default, these routines parse pathnames using your operating system's normal conventions for directory separators by consulting the `$^O` (`$OSNAME`) variable, which holds a string identifying the platform you're running on. That value was determined when Perl was built and installed. You can change the default by calling the `fileparse_set_fstype` routine. This alters the behavior of subsequent calls to the File::Basename functions:

>     fileparse_set_fstype("MacOS");
>     $path = "Hard%20Drive:System%20Folder:README.txt";
>     ($name,$dir,$ext) = fileparse($path,'\..*');

>     print "dir is $dir, name is $name, extension is $ext\n";
>     # dir is Hard%20Drive:System%20Folder, name is README, extension is .txt

To pull out just the extension, you might use this:

>     sub extension {
>         my $path = shift;
>         my $ext = (fileparse($path,'\..*'))[2];
>         $ext =~ s/^\.//;
>         return $ext;
>     }

When called on a file like source.c.bak, this returns an extension of "`c.bak`", not just "`bak`". If you want "`.bak`" returned, use '`\.[^.]*`' as the second argument to `fileparse` (this will, of course, leave the filename as `source.c`).

When passed a pathname with a trailing directory separator, such as "`lib/`", `fileparse` considers the directory name to be "`lib/`", whereas `dirname` considers it to be "`.`".

### 9.10.4. See Also

The documentation for the standard File::Basename module (also in Chapter 32 of Programming Perl); the entry for `$^O` (`$OSNAME`) in perlvar(1), and in the "Special Variables in Alphabetical Order" section of Chapter 28 of Programming Perl

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