[Appendix A] A.12 Chapter 13, File and Directory Manipulation
Author: Randal Schwartz, Tom Christiansen & Larry Wall
Date: 1999-07-02T01:37:01Z

#

| Appendix A Exercise Answers |

## A.12 Chapter 13, File and Directory Manipulation

1. Here's one way to do it:

       unlink @ARGV;

   Yup, that's it. The `@ARGV` array is a list of names to be removed. The `unlink` operator takes a list of names, so we just marry the two, and we're done.

   Of course, this doesn't handle error reporting, or the `-f` or `-i` options, or anything like that, but that'd just be gravy. If you did that, good!

2. Here's one way to do it:

       ($old, $new) = @ARGV; # name them
       if (-d $new) { # new name is a directory, need to patch it up
           ($basename = $old) =~ s#.*/##s; # get basename of $old
           $new .= "/$basename"; # and append it to new name
       }
       rename($old,$new) || die "Cannot rename $old to $new: $!";

   The workhorse in this program is the last line, but the remainder of the program is necessary for the case where the name we are renaming to is a directory.

   First, we give understandable names to the two elements of `@ARGV`. Then, if the `$new` name is a directory, we need to patch it by adding the basename of the `$old` name to the end of the new name. This means that renaming /usr/src/fred to /etc results in really renaming /usr/src/fred to /etc/fred.

   Finally, once the basename is patched up, we're home free, with a `rename` invocation.

3. Here's one way to do it:

       ($old, $new) = @ARGV; # name them
       if (-d $new) { # new name is a directory, need to patch it up
           ($basename = $old) =~ s#.*/##s; # get basename of $old
           $new .= "/$basename"; # and append it to new name
       }
       link($old,$new) || die "Cannot link $old to $new: $!";

   This program is identical to the previous program except for the very last line, because we're linking, not renaming.

4. Here's one way to do it:

       if ($ARGV[0] eq "-s") { # wants a symlink
           $symlink++; # remember that
           shift(@ARGV); # and toss the -s flag
       }
       ($old, $new) = @ARGV; # name them
       if (-d $new) { # new name is a directory, need to patch it up
           ($basename = $old) =~ s#.*/##s; # get basename of $old
           $new .= "/$basename"; # and append it to new name
       }
       if ($symlink) { # wants a symlink
           symlink($old,$new);
       } else { # wants a hard link
           link($old,$new);
       }

   The middle of this program is the same as the previous two exercises. What's new is the first few lines and the last few lines.

   The first few lines look at the first argument to the program. If this argument is `-s`, the scalar variable `$symlink` is incremented, resulting in a value of `1` for the variable. The `@ARGV` array is then shifted, removing the `-s` flag. If the `-s` flag isn't present, there's nothing to be done, and `$symlink` will remain `undef`. Shifting the `@ARGV` array occurs frequently enough that the `@ARGV` array is the default argument for `shift`; that is, we could have said:

         shift;

   in place of

         shift(@ARGV);

   The last few lines look at the value of `$symlink`. It's going to be either `1` or `undef`, and based on that, we either `symlink` the files or `link` them.

5. Here's one way to do it:

       foreach $f (<*>) {
           print "$f -> $where\n" if defined($where = readlink($f));
       }

   The scalar variable `$f` is set in turn to each of the filenames in the current directory. For each name, `$where` gets set to the `readlink()` of that name. If the name is not a symlink, the `readlink` operator returns `undef`, yielding a false value for the `if` test, and the `print` is skipped. But when the `readlink` operator returns a value, the `print` displays the source and destination symlink values.

A.11 Chapter 12, Directory Access |  | A.13 Chapter 14, Process Management