• No results found

Improving on User Commands Overview

#12 Building a Shell Script Library

Chapter 2: Improving on User Commands Overview

A typical Unix or Linux system includes hundreds of commands, which, when you factor in starting flags and the combinations of commands possible with pipes, should produce millions of different ways to work on the command line. Plenty of choices for anyone, right? Well, no. In fact, for all its flexibility, you can't always get what you want. Unlike other operating systems, however, with Unix you can usually cobble together something that'll do the trick quite easily, whether it's downloading some nifty new version of a utility with additional capabilities (particularly from the great GNU archive at http://www.gnu.org/), creating some aliases, or dipping your toe into the shell scripting pond. But before we go any further, here's a bonus script. If you're curious about how many commands are in your PATH, this simple shell script will do the trick:

#!/bin/sh

# How many commands: a simple script to count how many executable # commands are in your current PATH.

myPATH="$(echo $PATH | sed -e 's/ /~~/g' -e 's/:/ /g')" count=0 ; nonex=0

for dirname in $myPATH ; do

directory="$(echo $dirname | sed 's/~~/ /g')" if [ -d "$directory" ] ; then

for command in $(ls "$directory") ; do if [ -x "$directory/$command" ] ; then count="$(($count + 1))" else nonex="$(($nonex + 1))" fi done fi done

echo "$count commands, and $nonex entries that weren't executable"

exit 0

This script counts the number of executable files, rather than just the number of files, and reveals that Red Hat Linux 8 ships with 1,203 commands and 4 nonexecutables in a standard PATH, Mac OS X (10.2, with the developer options installed) has 1,088 commands and 25 nonexecutables, and Solaris 9 has an impressive 1,700 commands with 42 nonexecutables in the default PATH.

The scripts explored in this chapter are all similar to the simple script just given in that they add fun or useful features and capabilities without an overly high degree of complexity. Some of the scripts accept different command flags to allow even greater flexibility, and some also demonstrate how a shell script can be used as a wrapper, a program that intercedes to allow users to specify commands or command flags in a familiar notation and then translates those flags into the proper format and syntax required by the actual Unix command.

There's no question that the different flavors of Linux and Unix offer a large number of commands and executable scripts. Do we really need to add new ones? The answer is really based on the entire Unix philosophy: Unix is built upon the idea that commands should do one thing, and do it well. Word processors that have spell-check, find-file, and

email capabilities might work well in the Windows and Macintosh world, but on the command line, each of these functions should be separate and discrete. There are lots of advantages to this strategy, the most important being that each function can then be modified and extended individually, giving all applications that utilize it access to its new capabilities.

This strategy holds true across the board with Unix, and that's why the scripts in this chapter — and throughout the book — not only are helpful, but are a logical extension of the entire Unix philosophy. After all, 'tis better to extend and expand than to build complex, incompatible versions of commands for your own installation.

#14 Formatting Long Lines

If you're lucky, your Unix system already includes the fmt command, a program that's remarkably useful if you work with text with any frequency. From reformatting email to filling in paragraphs in documents (that is, making sure that as many words as possible are on each line of the text), fmt is a helpful utility to know.

But some Unix systems don't include fmt, particularly legacy systems at universities, which often have a fairly minimalistic implementation. As it turns out, the nroff command, which has been part of Unix since the very beginning, can be utilized in a short shell script to achieve the same result of wrapping long lines and filling in short lines to even up line lengths.

The Code

#!/bin/sh

# A version of fmt, using nroff. Adds two useful flags: -w X for line width # and -h to enable hyphenation for better fills.

while getopts "hw:" opt; do case $opt in h) hyph=1 ;; w) width="$OPTARG" ;; esac done shift $(($OPTIND - 1)) nroff << EOF .ll ${width:-72} .na .hy ${hyph:-0} .pl 1 $(cat "$@") EOF exit 0

How It Works

This succinct script offers two different command flags, -w X to specify that lines should be wrapped when their width exceeds X characters (the default is 72) and -h to enable hyphenation, filling the lines more and improving the final results. Notice the test to check for starting flags: A while loop uses getopts to step through the options, then uses shift $(($OPTIND - 1)) to throw all the arguments away once they've been processed.

The other, perhaps more important technique demonstrated here is the use of a here document to feed multiple lines of input to a command. The odd double-input-redirect sequence nroff <<EOF allows you to easily have a here document, a section of the script that's treated as if it were typed in on the command line. Using the here document, the script outputs all of the necessary nroff commands and then calls the cat command with the requested filename or filenames to process. The cat command's output is then fed directly to nroff. This is a technique that will appear frequently in the scripts presented in this book, and it's one well worth experimenting with!

Running the Script

This script can be included in a pipe, or it can have filenames specified on the command line, but usually it would be part of an external pipe invoked from within an editor like vi or vim (e.g., !}fmt) to format a paragraph of text.

The Results

The following example enables hyphenation and specifies a maximum width of 50 characters: $ fmt -h -w 50 014-ragged.txt

So she sat on, with closed eyes, and half believed herself in Wonderland, though she knew she had but to open them again, and all would change to dull reality--the grass would be only rustling in the wind, and the pool rippling to the waving of the reeds--the rattling teacups would change to tin- kling sheep-bells, and the Queen's shrill cries to the voice of the shepherd boy--and the sneeze of the baby, the shriek of the Gryphon, and all the other queer noises, would change (she knew) to the confused clamour of the busy farm-yard--while the lowing of the cattle in the distance would take the place of the Mock Turtle's heavy sobs.

Compare this with the following ouput, generated using the default width and no hyphenation: $ fmt 014-ragged.txt

So she sat on, with closed eyes, and half believed herself in

Wonderland, though she knew she had but to open them again, and all would change to dull reality--the grass would be only rustling in the wind, and the pool rippling to the waving of the reeds--the rattling teacups would change to tinkling sheep-bells, and the Queen's shrill cries to the voice of the shepherd boy--and the sneeze of the baby, the shriek of the Gryphon, and all the other queer noises, would change (she knew) to the confused clamour of the busy farm-yard--while the lowing of the cattle in the distance would take the place of the Mock Turtle's heavy sobs.