< Zurück | Inhalt | Weiter >

1.3.10 The Shell Revisited

Most Linux shells—the command interpreters—can be considered program- ming languages in their own right. That is, they have variables and control structures—if statements, for loops, and so on. While the syntax can be subtly different between shells, the basic constructs are all there.


Entire books can be—and have been—written on shell programming. (It’s one of our favorite subjects to teach.) Programs written in the shell lan- guage are often called shell scripts. Such scripts can be powerful yet easy to write (once you are familiar with the syntax) and can make you very productive in dealing with all those little housekeeping tasks that accompany program development. All you need to do (dangerous words, no?) is to put commands in a text file and give the file execute permissions. But that’s a subject for another day.

Some elements of shell scripting, however, are useful even if you never create a single shell script. Of these, perhaps the most important to know (especially for Java programmers) is how to deal with shell variables.



NOTE

We’ll be describing the syntax for bash, the default shell on most Linux distributions. The syntax will differ for other shells, but the concepts are largely the same.

image


Any string of alphanumeric or underscore characters can be used as the name of a variable. By convention shell variables typically use uppercase names—but that is only convention (although it will hold true for most if not all of our examples, too). Since commands in Linux are almost always lowercase, the use of uppercase for shell variables helps them to stand out.

Set the value of a shell variable with the familiar method—the equal sign:


$ FILE=/tmp/abc.out

$


This has assigned the variable FILE the value /tmp/abc.out. But to make use of the value that is now in FILE, the shell uses syntax that might not be familiar to you: The name must be preceded with a “$”.

Shell variables can be passed on to other environments if they are exported,

but they can never be passed back up. To set a shell variable for use by your current shell and every subsequent subshell, export the variable:


$ export FILE

$


You can combine the assignment of a value with the exporting into one step. Since repeating the export doesn’t hurt, you will often see shell scripts use the export command every time they do an assignment, as if it were part of the assignment syntax—but you know better.


$ export FILE="/tmp/way.out"

$



image

NOTE

The shell uses the dollar sign to distinguish between the variable name and just text of the same letters. Consider the following example:


$ echo first > FILE

$ echo second > TEXT

$ FILE=TEXT

$ cat FILE first

$


The cat command will dump the contents of the file named FILE to the screen—and you should see first. But how would you tell the shell that you want to see the contents of the file whose name you have put in the shell variable FILE? For that you need the “$”:


$ cat $FILE second

$


This is a contrived example, but the point is that shell syntax supports ar- bitrary strings of characters in the command line—some of them are filenames, others are just characters that you want to pass to a program. It needs a way to distinguish those from shell variables. It doesn’t have that problem on the assignment because the “=” provides the needed clue. To say it in computer science terms, the “$” syntax provides the R-value of the variable. (Not the insulation R-value, but what you expect when a variable is used on the Right- hand-side of an assignment operator, as opposed to the L-value used on the Left-hand-side of an assignment operator.)


There are several shell variables that are already exported because they are used by the shell and other programs. You may need or want to set them to customize your environment. Since they are already exported, you won’t need to use the export command and can just assign a value, but it doesn’t hurt.


The most important shell variable to know is PATH. It defines the directo- ries in the filesystem where the shell will look for programs to execute. When you type a command like ls or javac the shell will look in all of the directories specified in the PATH variable, in the order specified, until it finds the executable.


$ echo $PATH

/usr/local/bin:/usr/bin:/usr/X11R6/bin:/bin:.

$


The PATH shown in the example has five directories, separated by colons (“:”). (Note the fifth one, the “.”; it says to look in the current directory.) Where do you suppose it will find cat? You can look for it yourself by search- ing in each directory specified in PATH. Or you can use the which command:


$ which cat

/bin/cat

$


Some commands (like exit) don’t show up, since they are built into the shell. Others may be aliases—but that opens a whole other topic that we aren’t covering here. Just remember that each directory in the PATH variable is exam- ined for the executable you want to run. If you get a command not found error, the command may be there, it just may not be on your PATH.

To look at it the other way around: If you want to install a command so that you can execute it from the command line, you can either always type its full pathname, or (a more user-friendly choice) you can set your PATH variable to include the location of the new command’s executable.

So where and how do you set PATH? Whenever a shell is started up, it reads some initialization files. These are shell scripts that are read and executed as if they were typed by the user—that is, not in a subshell. Among other actions, they often set values for variables like PATH. If you are using bash, look at

.bashrc in your home directory.

Shell scripts are just shell commands stored in a file so that you don’t need to type the same commands and options over and over. There are two ways to run a shell script. The easiest, often used when testing the script, is


$ sh myscript


where myscript is the name of the file in which you have put your commands. (See Chapter 2 for more on how to do that.) Once you’ve got a script running the way you’d like, you might want to make its invocation as seamless as any other command. To do that, change its permissions to include the execution permission and then, if the file is located in a place that your PATH variable knows about, it will run as a command. Here’s an example:


$ chmod a+rx myscript

$ mv myscript ${HOME}/bin

$ myscript

... (script runs)

$


The file was put into the bin directory off of the home directory. That’s a common place to put homebrew commands. Just be sure that $HOME/bin is in your PATH, or edit .bashrc and add it.

If you want to parameterize your shell, you’ll want to use the variables $1,

$2, and so on which are given the first, second, and so on parameters on the command line that you used to invoke your script. If you type myscript Account.java then $1 will have the value Account.java for that invocation of the script.

We don’t have the space to go into all that we’d like to about shell pro- gramming, but let us leave you with a simple example that can show you some of its power. Used in shell scripts, for loops can take a lot of drudgery out of file maintenance. Here’s a simple but real example.

Imagine that your project has a naming convention that all Java files asso- ciated with the user interface on your project will begin with the letters “UI”. Now suppose your boss decides to change that convention to “GUI” but you’ve already created 200 or more files using the old naming convention. Shell script to the rescue:


for i in UI*.java do

new="G${i}"

echo $i ' ==> ' $new mv $i $new

done


You could just type those commands from the command line—that’s the nature of shell syntax. But putting them into a file lets you test out the script without having to type it over and over, and keeps the correct syntax once


you’ve got it debugged. Assuming we put those commands into a file called

myscript, here’s a sample run:


$ myscript

UI_Button.java ==> GUI_Button.java UI_Plovar.java ==> GUI_Plovar.java UI_Screen.java ==> GUI_Screen.java UI_Tofal.java ==> GUI_Tofal.java UI_Unsov.java ==> GUI_Unsov.java

...

$


Imagine having to rename 200 files. Now imagine having to do that with a point-and-click interface. It could take you all morning. With our shell script, it will be done in seconds.

We can’t hope to cover all that we’d like to about shell scripting. Perhaps we have been able to whet your appetite. There are lots of books on the subject of shell programming. We’ve listed a few at the end of this chapter.