Shell Scripts

The Problem

You have a thousand C files in your directory (these end in '.c' by convention) and you need to correct a typo made in these files. You can solve this problem with a few simple lines of code.

Changing one file: Using ed

Consider the simplest problem: making the changes in one file. You can do it by hand, but this can only be automated at an extreme cost to yourself. We'll use the command ed to do the job for us. The manual pages say that ed is a line-oriented text editor: this means it reads each line of a text file and performs a sequence of actions modifying the text. It then stores the line in a buffer, and will only rewrite the file if the user requests the changes to the file are saved. ed is unusual in that it accepts its commands from standard input--which will be your keyboard if you type
       ed  file
you will recieve a blank line: % ed is expecting input. Typing q will move you out of ed and back to the shell prompt. A typical session with ed will look as follows:
       % ed  file
      27
      comand
      comand
      comand
      w
      q
      25
The w tells ed to save your changes back to the file. The number that is displayed before the first command is the number of bytes in file, the last number is the number of bytes now in file after it was edited. These are % ed's response to you. You can learn about the commands ed excepts from the manual pages.

Automating ed from Here

Do you see a problem with using ed? It has not saved much time over manually opening-up each document. The Bash shell provides a nice facility that provides the needed bridge: we can redirect standard input to read from Here (wherever that may be.) Here is an example:
       % ed  file   <<TEXT
      >comand
      >comand
      >comand
      >w
      >q
      >TEXT
Notice that there is no response from ed until the final TEXT is typed; also there is now a prompt > displayed. When you add <<TEXT to the end of a command, Bash will wait for you to type some text, then direct your text to standard input for the command; you inform Bash you are finished by typing TEXT.

Using Here to Solve the Problem over There

The redirection is cute, but so far it still requires you to be Here at the keyboard. The key though is that you no longer need to be at the keyboard to feed commands to ed: you could be anywhere. You can open-up a file (lets call it myscript) and type:

ed  file   <<TEXT
comand
comand
comand
w
q
TEXT

To execute the contents of the file, you simple type on the command line
       % bash  myscript
and voilà, you have executed the commands to ed from a file, not your keyboard. You now have your first shell script.

Shell Scripting: Bring out the Heavy Artillery

I have been steering you along, but we still do not seem to be any closer to solving our problem of editing 1000 files. Our "script" requires that we change the script for each file in our directory we want to change. Then we must type a command on the prompt to execute this. Very true. Now, lets bring-out the heavy cannonade: loops and variables. The Bash shell can be programed to automate this process by adding a couple of lines to our script:

for file in *.c
    do
ed $file  <<TEXT
comand
comand
comand
w
q
TEXT
    done

The first line of code tells Bash that for each of our files ending in ".c" in the current directory, do the following routine, until you reach done. In the Bash shell variables begin with '$', as in $file. Now, when we type:
       % bash  myscript
Bash will make the changes to every one of our thousand files.

Making a Script File Act like a Command

This last section is for simple aesthetics: we do not need to type bash every time we want to run our script. Suppose we want to re-use the script, do we really want to remember that we have to run it using bash? You can use the following simple steps to convert your bash or any other script such as a gawk script to a simple command:

  1. Find out the location of the executable file for bash (or gawk):
       which bash
  2. On the first line of your script add:
      #!/bin/bash
    or whatever location was returned to you from step 1. When you execute a text file, the shell will look at the first line to see what program must be called to interpret the file. This could be the shell itself, or any other program (like gawk) which can read a scripting language.)
  3. Make your file executable: you will need to give execution permission for the file.
  4. Type the file on the command line. If it does not execute, it is because the current directory is not among the $PATH directories in Bash's search. You will need to tell Bash where to look for your command: append "./" to the beginning of your command. This informs Bash the location of the file is in the current directory.