## 10.3. The system() Function

The system() function executes a command supplied as an expression.[68] It does not, however, make the output of the command available within the program for processing. It returns the exit status of the command that was executed. The script waits for the command to finish before continuing execution. The following example executes the mkdir command:

> [68]The system() function is modeled after the standard C library function of the same name.

>     BEGIN { if (system("mkdir dale") != 0)
>     		print "Command Failed" }

The system() function is called from an if statement that tests for a non-zero exit status. Running the program twice produces one success and one failure:

>     $ awk -f system.awk
>     $ ls dale
>     $ awk -f system.awk
>     mkdir: dale: File exists
>     Command Failed

The first run creates the new directory and system() returns an exit status of 0 (success). The second time the command is executed, the directory already exists, so mkdir fails and produces an error message. The "Command Failed" message is produced by awk.

The Berkeley UNIX command set has a small but useful command for troff users named soelim, named because it "eliminates" ".so" lines from a troff input file. (.so is a request to include or "source" the contents of the named file.) If you have an older System V system that does not have soelim, you can use the following awk script to create it:

>     /^\.so/ { gsub(/"/, "", $2)
>     		system("cat " $2)
>     		next
>     		}
>     { print }

This script looks for ".so" at the beginning of a line, removes any quotation marks, and then uses system() to execute the cat command and output the contents of the file. This output merges with the rest of the lines in the file, which are simply printed to standard output, as in the following example.

>     $ cat soelim.test
>     This is a test
>     .so test1
>     This is a test
>     .so test2
>     This is a test.
>     $ awk -f soelim.awk soelim.test
>     This is a test
>     first:second
>     one:two
>     This is a test
>     three:four
>     five:six
>     This is a test.

We don't explicitly test the exit status of the command. Thus, if the file does not exist, the error messages merge with the output:

>     $ awk -f soelim.awk soelim.test
>     This is a test
>     first:second
>     one:two
>     This is a test
>     cat: cannot open test2
>     This is a test.

We might want to test the return value of the system() function and generate an error message for the user. This program is also very simplistic: it does not handle instances of ".so" nested in the included file. Think about how you might implement a version of this program that did handle nested ".so" requests.

This example is a function prompting you to enter a filename. It uses the system() function to execute the test command to verify the file exists and is readable:

>     # getFilename function -- prompts user for filename,
>     #   verifies that file exists and returns absolute pathname.
>     function getFilename(	file) {
>         while (! file) {
>     	printf "Enter a filename: "
>     	getline < "-" # get response
>     	file = $0
>     	# check that file exists and is readable
>     	# test returns 1 if file does not exist.
>     	if (system("test -r " file)) {
>     		print file " not found"
>     		file = ""
>     	}
>         }
>         if (file !~ /^\//) {
>     	"pwd" | getline # get current directory
>      	close("pwd")
>     	file = $0 "/" file
>         }
>         return file
>     }

This function returns the absolute pathname of the file specified by the user. It places the prompting and verification sequence inside a while loop in order to allow the user to make a different entry if the previous one is invalid.

The test -r command returns 0 if the file exists and is readable, and 1 if not. Once it is determined that the filename is valid, then we test the filename to see if it begins with a "/", which would indicate that the user supplied an absolute pathname. If that test fails, we use the getline function to get the output of the pwd command and prepend it to the filename. (Admittedly, the script makes no attempt to deal with "./" or "../" entries, although tests can be easily devised to match them.) Note the two uses of the getline function: the first gets the user's response and the second executes the pwd command.

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