home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Unix Power ToolsUnix Power ToolsSearch this book

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



Library Navigation Links

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