start page | rating of books | rating of authors | reviews | copyrights

Book HomeLearning Perl, 3rd EditionSearch this book

13.4. Making and Removing Directories

Making a directory inside an existing directory is easy. Just invoke the mkdir function:

mkdir "fred", 0755 or warn "Cannot make fred directory: $!";

Again, true means success, and $! is set on failure.

But what's that second parameter, 0755? That's the initial permission setting[295] on the newly created directory (you can always change it later). The value here is specified as an octal value because the value will be interpreted as a Unix permission value, which has a meaning based on groups of three bits each, and octal values represent that nicely. Yes, even on Windows or MacPerl, you still need to know a little about Unix permissions values to use the mkdir function. Mode 0755 is a good one to use, because it gives you full permission, but lets everyone else have read access but no permission to change anything.

[295]The permission value is modified by the umask value in the usual way. See umask(2) for further information.

The mkdir function doesn't require you to specify this value in octal -- it's just looking for a numeric value (either a literal or a calculation). But unless you can quickly can figure that 0755 octal is 493 decimal in your head, it's probably easier to let Perl calculate that. And if you accidentally leave off the leading zero, you get 755 decimal, which is 1363 octal, a strange permission combination indeed.

As we saw earlier (in Chapter 2, "Scalar Data"), a string value being used as a number is never interpreted as octal, even if it starts with a leading 0. So this doesn't work:

my $name = "fred";
my $permissions = "0755";  # danger... this isn't working
mkdir $name, $permissions;

Oops, we just created a directory with that bizarre 01363 permissions, because 0755 was treated as decimal. To fix that, use the oct function, which forces octal interpretation of a string whether or not there's a leading zero:

mkdir $name, oct($permissions);

Of course, if you are specifying the permission value directly within the program, just use a number instead of a string. The need for the extra oct function shows up most often when the value comes from user input. For example, suppose we take the arguments from the command line:

my ($name, $perm) = @ARGV;  # first two args are name, permissions
mkdir $name, oct($perm) or die "cannot create $name: $!";

The value here for $perm is interpreted as a string initially, and thus the oct function interprets the common octal representation properly.

To remove empty directories, use the rmdir function in a manner similar to the unlink function:

rmdir glob "fred/*";  # remove all empty directories below fred/

foreach my $dir (qw(fred barney betty)) {
  rmdir $dir or warn "cannot rmdir $dir: $!\n";
}

As with unlink, rmdir returns the number of directories removed, and if invoked with a single name, sets $! in a reasonable manner on a failure.

The rmdir operator fails for non-empty directories. As a first pass, you can attempt to delete the contents of the directory with unlink, then try to remove what should now be an empty directory. For example, suppose we need a place to write many temporary files during the execution of a program:

my $temp_dir = "/tmp/scratch_$$";       # based on process ID; see the text
mkdir $temp_dir, 0700 or die "cannot create $temp_dir: $!";
...
# use $temp_dir as location of all temporary files
...
unlink glob "$temp_dir/* $temp_dir/.*"; # delete contents of $temp_dir
rmdir $temp_dir;                        # delete now-empty directory

The initial temporary directory name includes the current process ID, which is unique for every running process and is accessed with the $$ variable (similar to the shell). We do this to avoid colliding with any other processes, as long as they also include their process ID as part of their pathname as well. (In fact, it's common to use the program's name as well as the process ID, so if the program is called quarry, the directory would probably be something like /tmp/quarry_$$.)

At the end of the program, that last unlink should remove all the files in this temporary directory, and then the rmdir function can delete the then-empty directory. However, if we've created subdirectories under that directory, the unlink operator fails on those, and the rmdir also fails. For a more robust solution, check out the rmtree function provided by the File::Path module of the standard distribution.



Library Navigation Links

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