## 41.8. Perl Boot Camp, Part 5: Perl Knows Unix

There are many built-in Perl operators that mimic Unix system calls and standard utilities, as are partially listed in Table 41-9. Those that aren't hardcoded into the language are often available through modules (Section 41.9). In fact, there are too many Unix-like operators to describe here, but this sampling should give you a good start.

#### Table 41-9. Perl filesystem functions

Function | Example | Description
--- | --- | ---
`chmod` | `chmod 0775,` `filenames` | Change file permission on given file or list of files; same as the system command.
`chown` | `chown` `UID``,` `GID``,` `filenames` | Change owner and group on given list of filenames; same as the system command.
`rename` | `rename` `oldname``,` `newname` | Change a file's name; similiar to mv.
`unlink` | `unlink` `filenames` | Unlink given filenames; deletes files that aren't hard linked elsewhere.
`system` | `system(``executable``)` | Create a subshell to execute an external command whose ouput isn't accessible to Perl.
`qx()` | `@output = qc(``executable``)` | Create a subshell to execute external command and return lines of output as an array to Perl; same as `''`.

One advantage Perl has over shell scripting is that Perl has filehandles. In Perl, files can only be created, edited, or read through special variables called filehandles. These variables have no funny punctuation prefixing them. It is customary to make filehandles all uppercase. The code below shows a typical way to read an existing file and echo its contents to the screen:

>     my $file = "your_filename";
>     open (IN, $file) || die "can't open $file: $!";
>     while (<IN>) {
>        print;
>     }
>     close (IN);

In this simple code, the `open` function is used to associate the filehandle `IN` with whatever filename you choose. If the `open` fails, the expression to the right of the logical OR will execute. The `die` function halts the program with the string provided. Here, that string includes the special variable `$!`, which contains the error message from the last failed system call (which here is `open`). If the `open` succeeds, `IN` can be read from with the `<>` operator. As noted earlier, this operator populates `$_` with the next line of input each time through the loop until there are no more lines to read. The `print` function will use `$_` if no other argument is passed to it. Although Perl will free all filehandles when the script exits, it's a good habit to close all filehandles you open.

Writing to files is almost as easy as reading from them. Consider this code:

>     my $file = "your_filename";
>     open (OUT, "> ". $file) || die "can't make $file: $!";
>     print OUT "<html><body><h1>hello, world</h1></body></html>\n";
>     close(OUT);

This snippet starts in a familiar way, but the `open` call is a little different. To tell Perl you want to create a new file or overwrite an existing one, simply prefix the filename with a `>`. If you wanted to append to an existing file, use `>>` instead. Now you can print to that file by passing the filehandle to `print` (notice there's no comma after the filehandle). Here, a simple HTML file is being created.

You can also read directories in Perl. The following code looks in the current directory and describes each file as a directory, symbolic link, or regular file.

>     opendir (DIR, ".") || die "error: $!";

>     while (my $file = readdir(DIR)) {
>         print "$file -> ";

>         if ( -d $file ) {
>           print "directory\n";

>         } elsif ( -l $file ) {
>           print "symlink\n";

>         } else{
>           print "file\n"
>         }
>     }
>     closedir (DIR);

To read directories, use the `opendir` function, which has a similiar interface to `open`'s. Unfortunately, the `<>` operator won't work on directory handles, so use the `readdir` command to iterate over each file in the directory. Perl provides file test operators, like those in the Bourne shell, to determine what kind of file its argument is. The `-d` operator tests whether a file is a directory, while the `-l` operator tests whether a file is symbolic link. Perl doesn't have a switch operator like C, but you can tack on as many `elsif` blocks as you need. What's not shown here is how to create a directory. Just as you would at the shell prompt, Perl provides a `mkdir` function that takes an octal number (which must start with zero!) and the name of the directory to create. Pretty simple.

In /etc/passwd and in password files for CVS and Apache, user passwords are stored as a string that has been passed through a one-way hashing algorithm (such as DES), usually using the system's `crypt(3)` system call. Perl provides access to this system call with a function of the same name. The following code prompts users for a new password for a fictional program and creates its own password file.

>     print "Username: \n";
>     my $user = <>;
>     print "Password: \n";
>     my $pass = <>;

>     chomp($user, $pass);
>     my $crypt = crypt($pass, substr($user, 0, 2));
>     open (OUT, ">>passwd") || die "error: $_";
>     print OUT "$user;$crypt;". localtime( ) . "\n";
>     close (OUT);

After collecting the username and password from the user, the `chomp` function removes the trailing newline from the input just collected. The `crypt` function expects the string to be hashed and a random two-character salt. Here, the first two characters of the username are used, via the `substr` function. The line written to the password file consists of a semicolon-separated list of the username, the hashed password, and a date stamp of when the account was added. Here, the `localtime` function call is used in scalar context because of the concatenation operator. This produces a human-readable string like `Sat Mar 16 21:17:44` `2002`. Used in list context, `localtime` returns a nine element list that's not easily consumed by human eyes (see Programming Perl, published by O'Reilly, for more details on scalar versus list context).

This section hardly scratched the surface of using Perl as a system administration tool. Many books have been written on this very topic, including O'Reilly's Perl for System Administration.

-- JJ

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