[Chapter 45] Shell Programming for the Initiated
Author: Jerry Peek, Tim O'Reilly & Mike Loukides
Date: 1998-08-04T21:54:15Z

#

| Chapter 45 |

# 45. Shell Programming for the Initiated

Contents:
Beyond the Basics
The Story of : # #!
Don't Need a Shell for Your Script? Don't Use One
Fun with #!
A File That Shows Itself... and What #! Does
Making Sure Your Script Runs with Bourne Shell, Without #!
The exec Command
Handling Signals to Child Processes
The Unappreciated Bourne Shell ":" Operator
Removing a File Once It's Opened - for Security and Easy Cleanup
The Multipurpose jot Command
Parameter Substitution
Save Disk Space and Programming: Multiple Names for a Program
Finding the Last Command-Line Argument
How to Unset all Command-Line Parameters
Standard Input to a for Loop
Making a for Loop with Multiple Variables
Using basename and dirname
A while Loop with Several Loop Control Commands
Overview: Open Files and File Descriptors
n>&m: Swap Standard Output and Standard Error
Handling Files Line-by-Line
The Ins and Outs of Redirected I/O Loops
A Shell Can Read a Script from its Standard Input, But...
Shell Scripts On-the-Fly from Standard Input
Quoted hereis Document Terminators: sh vs. csh
Turn Off echo for "Secret" Answers
Quick Reference: expr
Testing Characters in a String with expr
Grabbing Parts of a String
Nested Command Substitution
A Better read Command: grabchars
Testing Two Strings with One case Statement
Arrays in the Bourne Shell
Using a Control Character in a Script
Shell Lockfile

## 45.1 Beyond the Basics

This chapter has a bunch of tricks and techniques for programming with the Bourne shell. Some of them are documented but hard to find; others aren't documented at all. Here is a summary of this chapter's articles:

- The first group of articles is about making a file directly executable with `#!` on the first line. On many versions of UNIX (see article 44.4), an executable file can start with a first line like this:

  >     #!/path/to/interpreter

  The kernel will start the program named in that line and give it the file to read. Chris Torek's Usenet classic, article 45.2, explains how `#!` started. Article 45.3 explains that your "shell scripts" may not need a shell at all. Article 45.4 will give you a few grins as it shows unusual examples of `#!`-and article 45.5 has experiments to help you understand what `#!` does. If your UNIX doesn't have `#!`, the trick in article 45.6 will let you be sure your scripts run with the Bourne shell.

  Scripts using an interpreter that isn't a shell are in articles 25.11, 25.12, and 35.8.

- The next five articles are about processes and commands. The exec command, article 45.7, replaces the shell with another process; it can also be used to change input/output redirection (see below). The trap command can control how signals are passed to child processes; see article 45.8. The `:` (colon) operator evaluates its arguments and returns a zero status - article 45.9 explains why you should care. UNIX keeps a file on-disk once it's been opened; as article 45.10 explains, this has its ups and downs. The jot command, article 45.11, is useful for all kinds of operations with lists of numbers and characters.

- Next are techniques for handling variables and parameters. Parameter substitution, explained in article 45.12, is a compact way to test, set, and give default values for variables. You can use the `$0` parameter and UNIX links to make the same script have multiple names and do multiple things; see article 45.13. Article 45.14 shows the easy way to get the last command-line argument. Article 45.15 has an easy way to remove all the command-line arguments.

- Four articles cover sh loops. A for loop usually reads a list of single arguments into a single shell variable. Article 45.16 shows how to make the for loop read from standard input. Article 45.17 has techniques for making a for loop set more than one variable. The dirname and basename commands can be used to split pathnames with a loop; see article 45.18. A while loop can have more than one command line at the start; see article 45.19.

- Next is an assortment of articles about input/output. Article 45.20 introduces open files and file descriptors - there's more to know about standard input/output/error than you might have realized! Article 45.21 has a look at file descriptor handling in the Bourne shell, swapping standard output and standard error. The shell can redirect the I/O from all commands in a loop at once; article 45.22 explains one use for this technique and article 45.23 explains good and bad points of doing this.

- The shell can read commands directly from a shell script file. As article 45.24 points out, a shell can also read commands from its standard input, but that can cause some problems. Article 45.25 shows one place scripts from stdin are useful: writing a script that creates another script as it goes.

  Next are two articles about miscellaneous I/O. One gotcha with the here-document operator (for redirecting input from a script file) is that the terminators are different in the Bourne and C shells; article 45.26 explains. Article 45.27 shows how to turn off echoing while your script reads a "secret" answer such as a password.

- Three articles- 45.28, 45.29, and 45.30- show uses for the versatile expr expression-handling command. Article 45.31. covers multiple command substitution (9.16). The grabchars program in article 45.32 is similar to read (44.13)- but grabchars doesn't need a RETURN after the answer; grabchars also can prompt and do basic tests on the answer.

  Article 45.33 shows a trick for making one case statement (44.5) test two things at once. Article 45.34 has a trick for simulating arrays in the Bourne Shell. Article 45.35 uses echo and tr to get a control character in a script without typing the literal character into the file. Finally, article 45.36 has a simple technique for getting exclusive access to a file or other system resource.

- JP

44.23 Reading Files with the . and source Commands |  | 45.2 The Story of : # #!