[Chapter 10] 10.3 The system() Function
Author: Dale Dougherty & Arnold Robbins
Date: 1998-08-03T21:01:40Z

#

| Chapter 10 The Bottom Drawer |

## 10.3 The system() Function

The `system()` function executes a command supplied as an expression.[3] 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:

> [3] 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.

10.2 The close() Function |  | 10.4 A Menu-Based Command Generator