The "#!" syntax is an alternative syntax for invoking awk from a shell script. It has the advantage of allowing you to specify awk parameters and filenames on the shell-script command line. The "#!" syntax is recognized on modern UNIX systems, but is not typically found in older System V systems. The best way to use this syntax is to put the following line as the first line[6] of the shell script:
[6] Note that the pathname to use is system-specific.
#!/bin/awk -f
"#!" is followed by the pathname that locates your version of awk and then the -f option. After this line, you specify the awk script:
#!/bin/awk -f { print $1 }
Note that no quotes are necessary around the script. All lines in the file after the first one will be executed as though they were specified in a separate script file.
A few years ago, there was an interesting discussion on the Net about the use of the "#!" syntax that clarified how it works. The discussion was prompted by a 4.2BSD user's observation that the shell script below fails:
#!/bin/awk { print $1 }
while the one below works:
#!/bin/sh /bin/awk '{ print $1 }'
The two responses that we saw were by Chris Torek and Guy Harris and we will try to summarize their explanation. The first script fails because it passes the filename of the script as the first parameter (argv[1] in C) and awk interprets it as the input file and not the script file. Because no script has been supplied, awk produces a syntax error message. In other words, if the name of the shell script is "myscript," then the first script executes as:
/bin/awk myscript
If the script was changed to add the -f option, it looks like this:
#!/bin/awk -f { print $1 }
Then you enter the following command:
$myscript myfile
It then executes as though you had typed:
/bin/awk -f myscript myfile
NOTE: You can put only one parameter on the "#!" line. This line is processed directly by the UNIX kernel; it is not processed by the shell and thus cannot contain arbitrary shell constructs.
The "#!" syntax allows you to create shell scripts that pass command-line parameters transparently to awk. In other words, you can pass awk parameters from the command line that invokes the shell script.
For instance, we demonstrate passing parameters by changing our sample awk script to expect a parameter n:
{ print $1*n }
Assuming that we have a test file in which the first field contains a number that can be multiplied by n, we can invoke the program, as follows:
$ myscript n=4 myfile
This spares us from having to pass "$1" as a shell variable and assigning it to n as an awk parameter inside the shell script.
The masterindex, described in Chapter 12, uses the "#!" syntax to invoke awk. If your system does not support this syntax, you can change the script by removing the "#!", placing single quotes around the entire script, and ending the script with "$*", which expands to all shell command-line parameters.
Well, we've quite nearly cleaned out this bottom drawer. The material in this chapter has a lot to do with how awk interfaces with the UNIX operating system, invoking other utilities, opening and closing files, and using pipes. And, we have discussed some of the admittedly crude techniques for debugging awk scripts.
We have covered all of the features of the awk programming language. We have concentrated on the POSIX specification for awk, with only an occasional mention of actual awk implementations. The next chapter covers the differences among various awk versions. Chapter 12 is devoted to breaking down two large, complex applications: a document spellchecker and an indexing program. Chapter 13, A Miscellany of Scripts, presents a variety of user-contributed programs that provide additional examples of how to write programs.