Then edit the first line of Makefilefor the example program for this chapter and try running it to make surethat Mesa is set up properly on your computer.. This proprietary software, as
Trang 1The only thing at all complicated about this example is handling the events associatedwith the user clicking on the button object However, these events are handled with only
a few lines of code in the same way that we handled events in the AWT example gram in Listing 32.9:
pro-countButton.addMouseListener(
new java.awt.event.MouseAdapter() { public void mouseClicked(MouseEvent e) { countLabel.setText(“button clicked “ +
++count + “ times”);
} });
The addMouseListenermethod is used to associate an instance of the MouseListener
with a button (or any other component) Now, it is possible to define a separate class thatimplements the MouseListenerlistener interface (which requires defining five methods:
mouseClicked,mouseEntered,mouseExited,mousePressed, and mouseReleased).However, there is a MouseAdapterutility class that defines “do nothing” versions ofthese five methods In this code example, we are creating an anonymous inner class (forexample, it is an inner class with no name associated with it) that overrides the
mouseClicked Our mouseClickedmethod uses the setTextmethod to change the played text of a label In Listing 32.13 we import all classes and interfaces from thepackages java.awt(for the graphic components and containers) and java.awt.event
dis-(for the event-handling classes and interfaces), and from the package javax.swingto getthe Swing(or JFC) classes
In Listing 32.11, we define a static public mainmethod that is executed when wecompile and run this sample program by typing:
javac JFCSample.java java JFCSample
The JFCSampleprogram does not handle window closing events, so it must be terminated
by typing Ctrl+C in the terminal window where you run the program
Writing a Chat Program Using JFC
We will develop the ChatJFCprogram in this section It is almost identical to the
ChatAWTprogram, only it uses the JFC classes instead of the AWT classes Both grams were shown in Figure 32.2
pro-The sample program in Listing 32.12 that implements a chat client using JFC is a littlecomplex because the user interface has several components Each component is posi-tioned by an X-Y location in a panel and is sized to a specific width and height using the
setBoundsmethod Before looking at the code in Listing 32.12, you should look at the
Trang 2bottom of Figure 32.2, which shows the ChatJFCprogram running The ChatJFCgram uses the ChatEngineclass The interface to ChatEngineis very simple and wascovered in a previous section The ChatJFCclass implements the ChatListenerinterfaceand registers itself with an instance of ChatEngine This registration allows the chatengine object to call the receiveTextmethod (required to implement the ChatListener
pro-interface) in the ChatJFCclass
// File: ChatJFC.java import javax.swing.*; // swing 1.1 //import com.sun.java.swing.*; // swing 1.0 import java.awt.*;
import java.awt.event.*;
public class ChatJFC extends JFrame implements ChatListener{
JPanel jPanel1 = new JPanel();
JTextField myPortField = new JTextField();
JLabel label1 = new JLabel();
JLabel label2 = new JLabel();
JTextField hostField = new JTextField();
JLabel label3 = new JLabel();
JTextField portField = new JTextField();
JLabel label4 = new JLabel();
JTextField inputField = new JTextField();
JLabel label5 = new JLabel();
JButton listenButton = new JButton();
JButton connectButton = new JButton();
JButton disconnectButton = new JButton();
JButton quitButton = new JButton();
JTextArea outputField = new JTextArea();
JScrollPane jScrollPane1 = new JScrollPane();
protected ChatEngine chatEngine;
public ChatJFC() { super(“Chat with JFC GUI”);
chatEngine = new ChatEngine();
Trang 3Listing 32.12 CONTINUED
quitButton.addMouseListener(
new java.awt.event.MouseAdapter() { public void mouseClicked(MouseEvent e) { System.exit(0);
} });
if (e.getKeyCode() == ‘\n’) { chatEngine.send(inputField.getText()); }
} });
Integer.parseInt(myPortField.getText())); }
});
Trang 4connectButton.setBounds(175, 280, 136, 34);
connectButton.addMouseListener(
new java.awt.event.MouseAdapter() { public void mouseClicked(MouseEvent e) { chatEngine.connect(hostField.getText(), Integer.parseInt(portField.getText()));
} });
connectButton.setLabel(“Connect”);
disconnectButton.setBounds(315, 280, 127, 33);
disconnectButton.addMouseListener(
new java.awt.event.MouseAdapter() { public void mouseClicked(MouseEvent e) { chatEngine.connect(hostField.getText(), Integer.parseInt(portField.getText()));
} });
public void receiveText(String s) {
if (s == null) return;
output_string = output_string + s;
outputField.setText(output_string + “\n”);
} static public void main(String [] args) { new ChatJFC();
} }
Trang 5The ChatJFCprogram is very similar to the ChatAWTprogram I wrote the ChatJFCgram by copying the ChatAWTprogram and doing the following:
pro-• Adding the import swing (JFC) package statement
• Changing Labelto JLabel,Buttonto JButton, and so on
• Using the getContentPanemethod where required to get the internal container foradding components and setting the layout manager to null
Using Native Java Compilers
There are two native mode Java compilers under development, one by TowerJ (www.towerj.com) and the other by Cygnus (www.cygnus.com) At the time this chapterwas written (March 1999), the Cygnus compiler was available only in early test releases,but it looked promising The TowerJ compiler is a commercial product I have used it forthree programs, and I have seen performance improvements from a factor of four to afactor of 11 over using a JIT (Just In Time compiler) One of the benefits of Java is theportability of its byte code However, for server-side programs, giving up portability infavor of large performance improvements is often a good option
Summary
This short chapter has hopefully given you both a quick introduction to the Java languageand the motivation to study the language further There are many sources of informationfor programming Java on the Internet Because Web site links change, I will keep currentlinks to my favorite Java resources on the Internet at my Web site
(www.markwatson.com/books/linux_prog.html)
Many interesting topics were not covered in this short chapter, such as:
• Drawing graphics
• Writing applets that run inside of Web browsers
• More techniques for handling user interface events
If you are primarily a C or C++ programmer, I urge you to also learn Java I have beenusing C for 15 years and C++ for 10 years, but I prefer Java for most of my developmentwork Yes, it is true that Java programs will run slower than the equivalent C or C++ pro-grams However, after using Java for about 3 years, I believe that Java enables me towrite a large application in about half the time it takes to write the same application inC++ I have talked with other developers who agree that they are approximately twice asproductive when programming in Java instead of C or C++
Trang 6by Mark Watson
Trang 7The OpenGLAPI was developed at Silicon Graphics and has become an industry standardfor high-quality 3D graphics Although there are commercial ports of OpenGLto Linux, ahigh-quality public domain OpenGL-like implementation called Mesa has been written byBrian Paul Mesa can not be called OpenGLbecause it is not licensed from SiliconGraphics, but I have found it to be an effective tool for OpenGLprogramming on Linux.Mesa might be included with your Linux distribution Although I assume that you haveinstalled and are using Mesa, I will refer to OpenGLin this chapter I will keep a currentlink to the Mesa distribution on my web site.
The OpenGLAPI is complex We will use one simple example in this chapter to illustratehow to use the OpenGLauxiliary library to draw simple shapes, placing and rotating theshapes under program control We will also learn how to use lighting effects and how tochange the viewpoint For most 3D graphics applications (like games), you need a sepa-rate modeling program to create 3D shapes, and you also need specialized code to usethese shapes in OpenGLprograms The topics of modeling 3D images and using them in
OpenGLprograms is beyond the scope of this introductory chapter
Before reading this chapter, please download the latest Mesa distribution and install it inyour home directory The sample program for this chapter is located in the src/OpenGL
directory on the CD-ROM You will have to edit the first line of Makefileto reflect thepath in your home directory where you have installed Mesa The example program usesthe OpenGLUtilities Library (GLUT) OpenGLitself is operating system- and device-independent The GLUTlibrary allows programmers to initialize OpenGL, create windows,and so on in a portable way There are three example directories in the Mesa installationdirectory:book,demos, and samples Please make sure that building Mesa also built exe-cutables for the many sample programs in these three directories Then edit the first line
of Makefilefor the example program for this chapter and try running it to make surethat Mesa is set up properly on your computer A few of the example programs in theMesa distribution may not run with your graphics card; do not worry about this
Graphics Hardware
There are OpenGLsoftware interface implementations for most 3D graphics cards, so
OpenGLand Mesa will probably run efficiently on your computer unless you have a veryold graphics card Microsoft supports OpenGLon Windows 95, 98, and NT, so the pro-grams that you develop under Linux using Mesa will probably run with few modifica-tions under Windows I worked at a computer animation company, Angel Studios
Trang 8(www.angel.com), where we used proprietary software for rendering real-time 3D ics on a wide variety of hardware, including Nintendo Ultra-64, Windows, and SGIworkstations This proprietary software, as an option, used OpenGLto talk with graphicshardware.
graph-The Orbits Sample Program
There are many features of OpenGLthat we are not covering in the orbits example gram for this chapter (for example, the use of display lists and texture mapping) Thesample program in this section does illustrate several OpenGLprogramming techniques,but it is also simple enough for a tutorial example The example program orbits.cislocated in the src/OpenGLdirectory
pro-The sample program uses the GLUTfunction glutSolidSphereto draw both a large
“planet” and a small orbiting satellite This example demonstrates the following:
• Creating a window for OpenGLgraphics and initializing OpenGL
• Creating simple 3D objects using GLUT
• Placing objects anywhere in a three-dimensional space using X-Y-Z coordinates
• Rotating an object about any or all of the x-, y-, and z-axes
• Enabling the use of material properties so objects can be colored
• Enabling depth tests so that rendered objects close to the viewer correctly coverobjects that are obscured
• Handling keyboard events
• Updating OpenGLgraphics for animation effectsThese operations are performed using both the OpenGLcore API and the OpenGLutilitylibrary All OpenGLimplementations include the OpenGLutility library, so the simpleexample in this chapter should be easily portable to other operating systems and OpenGL
implementations
OpenGLuses a modeling coordinate system where the X coordinate moves increasinglytoward the right on the screen, the Y coordinate moves increasingly upward, and the zcoordinate increases looking into the screen The origin (for example, at X=Y=Z=0) islocated at the center of the screen
The sample program cycles viewing angle, plus smooth or flat shading, when you hit anykey (except for an escape, or q characters, that halt the program) while the program isrunning
Trang 9Figure 33.1 shows the orbitssample program running in the default smooth-shadedmode The background color was changed to white for this figure; the program on theCD-ROM has a black background.
F IGURE 33.1
The orbits gram running with smooth- shading.
In this chapter, we will use the following OpenGLutility library functions to initialize
OpenGL, the GLUTlibrary, and to create a window for drawing:
glutInit Initializes GLUTand OpenGL
glutInitDisplayMode Sets display properties (our example program will set
properties allowing for double buffering, depth ing, and use of RGB colors)
queu-glutInitWindowSize Sets the size of the main window
glutInitWindowPosition Positions the main window on the desktop or X
Windows display
glutCreateWindow Actually creates the main window
Trang 10The initialization code in the sample program looks like the following:
GLUT_DOUBLE Enables double buffering for smooth animation
GLUT_RGB Specifies the use of RGB color table
GLUT_DEPTH Enables the use of a depth buffer to determine when one
object is obscuring another in a scene
There are several GLUTutility functions for creating both wire frame and solid objects Tocreate a sphere, use either of the following:
void glutSolidSphere(GLdouble radius, GLint slices,
GLint stacks);
void glutWireSphere(GLdouble radius, GLint slices, GLint stacks);
Here,radiusis the radius of the sphere The slicesargument is the number of flatbands created around the z-axis The higher the number of slices, the rounder the sphere
The stacksargument is the number of flat bands along the z-axis The higher the slices
value, the rounder the sphere Lower slicesand stacksvalues produce shapes that aredrawn quicker A sphere is drawn (or rendered) centered at the origin in modeling coordi-nates (for example, when the OpenGLMatrix mode is in modeling mode; more on thislater)
To create a cube, use either of the following:
void glutSolidCube(GLdouble size);
void glutWireCube(GLdouble size);
The sizeargument is the length of any edge of the cube
To draw a cone, use either of the following:
void glutSolidCone(GLdouble base, GLdouble height,
GLint slices, GLint stacks);
void glutWireCone(GLdouble base, GLdouble height,
GLint slices, GLint stacks);
Trang 11The baseargument is the radius of the cone’s base The heightargument is the height ofthe cone The slicesargument is the number of flat bands drawn around the z-axis The
stacksargument is the number of flat bands drawn about the z-axis The center of thebase of the cone is placed at X=Y=Z=0 in the modeling coordinate system The cone
“points” along the z-axis
If you want to draw a torus, use either of the following GLUTfunctions:
void glutSolidTorus(GLdouble inner_radius,
GLdouble outer_radius, GLint nsides, GLint rings);
void glutWireTorus(GLdouble inner_radius,
GLdouble outer_radius, GLint nsides, GLint rings);
The inner_radiusand outer_radiusarguments are the inner and outer radii of thetorus The nsidesargument is the number of flat bands drawn for each radial section.The ringsargument is the number of radial bands
Placing Objects in 3D Space Using X-Y-Z Coordinates
Before placing objects in a 3D world, we need to make sure that OpenGLis in the modelmode This is accomplished by calling:
glMatrixMode(GL_MODELVIEW);
We can translate the origin of the model world to coordinates X, Y, and Z by calling:
glTranslatef(GLfloat X, GLfloat Y, GLfloat Z);
One problem that we have is remembering where we have moved the origin Fortunately,there are OpenGLutility functions that push the entire state of OpenGLonto a stack, whichpulls the state of OpenGLoff a stack These functions are:
glPushMatrix();
glPopMatrix();
In practice, we usually push the “matrix” (for example, the state of the OpenGLengine),perform drawing operations on one or more objects, then pop the “matrix” back off thestack The following example shows how to draw a sphere of radius equal to 1.0 atX=10, Y=0.0, and Z=1.0:
glPushMatrix();
{ glColor4f(1.0, 0.0, 0.0, 1.0); // make the sphere red glTranslatef(10.0, 0.0, 1.0); // translate the model
// coordinate system glutSolidSphere(1.0, 40, 40); // Draw a very detailed sphere } glPopMatrix();
Trang 12As a matter of programming style, I enclose within curly braces any operations betweenthe “push” and the “pop”; this improves the readability of the code In this example, wealso see a call to glColor4fthat is used to specify the red, green, and blue drawing col-ors (values are between 0.0 and 1.0) The fourth argument of glColor4fis the alpha
value; an alphavalue of 0.0 makes a transparent object—not too useful—and a value of1.0 makes an entirely opaque object In the sample program, try changing the alpha
value in the calls in displayto a value of 0.5 so that you can see through the renderedobjects
Rotating an Object About Any or All of the X-, Y-, and Z- Axes
Rotating objects created with the GLUTutilities for drawing simple shapes is a little morecomplicated than changing an object’s X-Y-Z location In the example program in dis- play, we draw a central planet that is centered at X=Y=Z=0 and a small satellite thatorbits around the central planet We will start by looking at the code for rotating the cen-tral planet about the origin (for example., X=Y=Z=0) of the model coordinate system:
// push matrix, draw central planet, then pop matrix:
glPushMatrix();
{ glRotatef((GLfloat)planet_rotation_period, 0.0, 1.0, 0.0);
glColor4f(1.0, 0.0, 0.0, 1.0);
glutSolidSphere(1.0, 10, 8); // Draw the central planet } glPopMatrix();
Here, we use a planet_rotationvariable that is incremented each time the OpenGL
scene is drawn This value ranges between 0.0 and 360.0 because the arguments to
glRotatefare in degrees, not radians The last three arguments of glRotatefspecify therotation axis The arguments (0.0, 1.0, 0.0) specify that the angle of rotation is about thepositive y-axis By slowly varying the value of planet_rotation_periodbetween 0.0and 360.0, the central planet slowly rotates
The placement and rotation of the satellite is more complex because we want to bothtranslate its position and to rotate it To do this, the code from the example program’s
displayfunction is as follows:
// push matrix, draw satellite, then pop matrix:
glPushMatrix();
{ glRotatef((GLfloat)central_orbit_period, 0.0, 1.0, 0.0);
Trang 13Initially, we call glRotatefto rotate the satellite about the origin—just as we did for thecentral planet It is important to realize that the satellite is centered at the origin until wemove it After rotating the coordinate system, we call glTranslateto move it to model-ing coordinates (1.9, 0.0, 0.0), and finally rotate the coordinate system once again to sim-ulate the satellite’s orbit around the planet.
Figure 33.2 shows the orbitssample program running in the flat-shaded mode Thebackground color was changed to white for this screen shot; the program on the CD-ROM has a black background
F IGURE 33.2
The orbits gram running with flat shading
The example program’s initfunction sets up the OpenGLenvironment The followingfunction call configures the OpenGLengine to allow us to later use drawing colors:
glEnable(GL_COLOR_MATERIAL);
By default, objects are flat-shaded; initalso configures the OpenGLengine to usesmooth-shading When you press the Spacebar, the example program switches betweensmooth- and flat-shading (and also cycles through one of three viewing positions) Thefollowing function call requests a smooth shading drawing model:
glShadeModel(GL_SMOOTH);
We can also useglClearColorto change the default background color for the window.The first three arguments are the red, green, and blue color values for the background;
Trang 14the last argument specifies the alpha (or transparency) of the background Here, to makethe background almost black, we use low values for the red, green, and blue background-color components Setting the background alpha to zero makes it totally transparent.
glClearColor(0.1, 0.1, 0.1, 0.0);
In Figure 33.1 and Figure 33.2, we set the background to white by passing the value 1.0for the first three arguments of glClearColor The example orbits.con the CD-ROMsets a black background, however
Enabling Depth Tests
The example program’s initfunction sets up the OpenGLenvironment to use a depth test
to hide obscured objects from view The following function call configures the OpenGL
engine to allow us to later use this depth-cueing:
glCullFace(GL_BACK);
glEnable(GL_DEPTH_TEST);
In addition to making these two calls, we need to add the GLUT_DEPTHoption when ting up the GLUTdisplay mode in the main function:
set-glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
Handling Keyboard Events
It is useful to be able to handle keyboard input in OpenGLgraphics programs Using the
GLUTlibrary, this is easily done using a Callback function that is called with the key
value whenever any key on the keyboard is pressed The sample program uses the lowing Callback function:
fol-void key_press_callback(unsigned char key, int x, int y)
We will use the first argument keyand ignore the last two arguments in the example gram We register this Callback function in the mainfunction by calling:
pro-glutKeyboardFunc(key_press_callback);
Effects
In the example program, we use a displayCallback function that is called by the GLUT
library whenever the window needs to be redrawn The function signature for display is:
Trang 15We register this Callback function in mainby calling:
ani-Sample Program Listing
We have seen pieces of most of the example program in the last few sections In this tion, we will list out the entire file with a few additional comments This example, asseen in Listing 33.1, uses a single includefile glut.hfor using both OpenGL/Mesa andthe OpenGLutility functions
#include <GL/glut.h>
void init(void) {
static int planet_rotation_period = 0;
static int satellite_rotation_period = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// push matrix, draw central planet, then pop matrix:
glPushMatrix();
{ glRotatef((GLfloat)planet_rotation_period, 0.0, 1.0, 0.0);
glColor4f(1.0, 0.0, 0.0, 1.0);
Trang 16glutSolidSphere(1.0, 10, 8); // Draw the central planet } glPopMatrix();
// push matrix, draw satellite, then pop matrix:
glPushMatrix();
{ glRotatef((GLfloat)central_orbit_period, 0.0, 1.0, 0.0);
glutPostRedisplay();
} void reshape(int w, int h) { glViewport(0, 0, w, h);
static int shade_flag = 0;
if (++count > 2) { count = 0;
shade_flag = 1 - shade_flag;
} glLoadIdentity();
switch (count) {
Trang 17{ case 27: /* escape character */
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
“canned” 3D shapes (such as spheres, cubes, cones, and so on), which are defined in the
OpenGLutility library More information about OpenGLis available at
http://www.opengl.org/
More information on Mesa can be found at:
http://www.opengl.org/Documentation/Implementations/Mesa.html
Trang 20I N T HIS C HAPTER
by Kurt Wall
Trang 21Within the first two days of becoming a Linux user in 1993, I wrote my first bashscript,
a very kludgy effort to automate my backups This anecdote illustrates how pervasiveshell scripting is in Linux In this chapter, I will give you a firm foundation in the basics
of bashshell programming
GNU’s bash(Bourne Again Shell, named in punning homage to the Bourne shell and itsauthor, Steven Bourne) is Linux’s default shell Written by Brian Fox and maintained byChet Ramey,bash’s most popular features are its rich command-line editing facilitiesand its job control abilities From the programmer’s perspective,bash’s chief advantagesare its customizability and the complete programming environment it provides, includingfunction definitions, integer math, and a surprisingly complete I/O interface As youmight expect of a Linux utility,bashcontains elements of all of the popular shells,Bourne, Korn, and C shell, as well as a few innovations of its own As of this writing, thecurrent release of bashis 2.0.3 Most Linux distributions, however, use the tried and test-
ed 1.14 version Nevertheless, I will cover bashversion 2, pointing out features notavailable in earlier versions as they arise, because version 2 is much closer to POSIXcompliance than version 1
Throughout this chapter, I assume that you are comfortable using bash, so my discussionfocuses on bash’s features from the shell programmer’s perspective By way of review,however, I will refresh your memory of bash’s wildcard operators and its special charac-ters
The command ls zi*matches zic2xpm,zip,zipcloak,zipgrep,zipinfo, and
zipsplit, but ls zi?only matches zip
Trang 22The set operators allow you to use either a range or a disjoint set of characters as cards To specify an inclusive range of characters, use a hyphen between characters Forexample, the set [a-o] includes all of the lowercase characters “a” through “o.” Use acomma to indicate a disjoint set, such as the range of characters between “a” and “h” andbetween “w” and “z” In bash’s set notation, this range of characters could be specifiedwith “[a-h,w-z]” If you want to look only for a few individual characters, such as all ofthe English vowels, the notation “[aeiou]” would do The “!” prefixing a set means to
wild-include everything not in the set So, an easy way to look for all of the consonants is to
write [!aeiou] The following examples illustrate using the set notation and also how you can use thewildcard operators with sets To list all of the files in the directory above whose secondletter is a vowel, you could write:
$ ls z[aeiou]*
This will match zeisstopnm,zip zipgrep,zipnote,zic2xpm,zipcloak,zipinfo, and
zipsplit On the other hand, to list the files that have only consonants as their secondletter, use lsz[!aeiou]*, which matches zcmp,zdiff,zforce,zgrep,zless,zmore, and
znew The command,ls *[0-9]*matches only those filenames containing at least onenumeric digit between zero and nine, which is zic2xpmin this case
Brace Expansion
Brace expansion is a more general case of the filename globbing enabled by wildcardcharacters The basic format of an expression using brace expansion follows:
[preamble]{str1[,str2[, ]]}[postscript]
Each string inside the braces will be matched with the optional preamble and postscript
For example, the following statement
$ echo c{ar,at,an,on}s
results in
cars cats cans cons
Because brace expressions can be nested, the preceding statement could be rewritten asfollows to obtain the same output:
Trang 23Special Characters
The wildcard and set operators are four examples of bash’s special ters that have a specific meaning to bash Table 34.1 lists all of the special characters,with a brief description of each one
Input and output redirection should be familiar to you Although I will discuss subshellslater in this chapter, it is important to note that all the commands between (and )areexecuted in a subshell Subshells inherit some of the environment variables, but not all ofthem This behavior is different from commands in a block (blocks are delimited by {
and }), which are executed in the current shell and thus retain all of the current ment
environ-The command separator,;, allows you to execute multiple bash commands on a singleline But more importantly, it is the POSIX-specified command terminator
Trang 24The comment character,#, causes bashto ignore everything from the character to theend of the line The difference between the strong quote and weak quote characters,
‘and “, respectively, is that the strong quote forces bash to interpret all special ters literally; the weak quote only protects some of bash’s special characters from interpretation as special characters
As you might expect,bash, has variables Usually they are character strings, but bash
also has special facilities for dealing with numeric (integer) values, too To assign a value
to a variable, use the following syntax:
varname=value
To obtain a variable’s value, you can use one of the following two formats:
$varname
${varname}
The second form,${varname}, is the more general format and also more difficult to type
However, you must use it to distinguish variables from trailing letters, digits, or scores For example, suppose you have a variable named MYNAMEand you want to displayits value followed by an underscore character You might be tempted to try the followingcommand:
under-$ echo under-$MYNAME_
but this attempt will fail because bashwill attempt to print the value of the variable
MYNAME_, not MYNAME In this situation, you must use the second syntax, as illustratedbelow:
$ echo ${MYNAME}_
Listing 34.1 illustrates this subtlety
7 echo ‘${MYNAME}_ yields: ‘ ${MYNAME}_
8 echo ‘$MYNAME_ yields: ‘ $MYNAME_
Trang 25The strong quotes on lines 7 and 8 prevent bashfrom expanding the variables As youcan see in the script’s output below,$MYNAME_is empty and prints nothing, but
${MYNAME}_produces the expected output
con-bashalso has three special positional parameters,“$#”,“$@”,and “$#” “$#”evaluates tothe number of positional parameters passed to a script or a function (not counting “$0”)
“$*”is a list of all the positional parameters, except “$0”, formatted as a single stringwith each parameter separated by the first character the $IFS, the internal field separator(another bashenvironment variable) “$@”, on the other hand, is all of the positionalparameters presented as N separate double-quoted strings
What is the difference between “$*”and “$@”? And why the distinction? The differenceallows you to treat command-line arguments in two ways The first format,“$*”, because
it is a single string, can be displayed more flexibly without requiring a lot of shell code
to do so “$@”, on the other hand, allows you to process each argument individuallybecause its value is N separate arguments Listing 34.2 illustrates the differences between
Trang 2610
11 cntparm “$*”
12 cntparm “$@”
13
14 echo -e “outside cntparm $*\n”
15 echo -e “outside cntparm $#\n”
This script’s output is as follows:
1 $ /posparm.sh Kurt Roland Wall
2 inside cntparm 1 parms: Kurt Roland Wall 3
4 inside cntparm 3 parms: Kurt Roland Wall
5
6 outside cntparm Kurt Roland Wall
7
8 outside cntparm Kurt Roland Wall
Lines 11 and 12 in particular illustrate the practical difference between the positionalparameters,$*and $@ For the time being, treat the function definition and calls as ablack box Line 11, using “$*”, passes the positional parameters as a single string, sothat cntparmreports a single parameter, as show on line 2 of the output list The secondcall to cntparm, however, passes the script’s command-line arguments as 3 separatestrings, so the cntparmreports three parameters (line 4) There is no functional differ-ence in the appearance of the parameters when printed, however, as lines 6 and 8 of theoutput make clear
The -eoption to the echocommand forces it to print the \n sequence as a new line(lines 8, 14, and 15) If you do not use the -eoption, do not force a new line with \n
because echoautomatically adds one to its output
I introduce many of bash’s operators in the course of discussing other subjects In thissection, however, I acquaint you with bash’s string- and pattern-matching operators
Later sections will use these operators frequently, so covering them now will make theother sections proceed smoothly
String Operators
The string operators, also called substitution operators in bashdocumentation, testwhether a variable is unset or null Table 34.2 lists these operators with a brief descrip-tion of each operator’s function
Trang 27Table 34.2 bashSTRINGOPERATORS
${var:-word} If var exists and is not null, returns its value, else
${var:=word} If var exists and is not null, returns its value, else
${var:+word} If var exists and is not null, returns word , else
returns null.
${var:?message} If var exists and is not null, returns its value, else
cur-rent command or script.
${var:offset[:length]} Returns a substring of var beginning at offset of
length length If length is omitted, the entire string
To illustrate, consider a shell variable statusinitialized to defined Using the first fourstring operators from Table 34.2 on statusresults in the following:
$ echo ${status:?Dohhh\! undefined}
bash: status: Dohhh! undefined
It was necessary to unset status a second time because the third command,echo tus:+undefined}, reset status to undefinedupon executing
Trang 28${sta-The substring operators listed at the bottom of Table 34.2 are especially useful for, well,obtaining substrings Consider a variable foowith the value Bilbo_the_Hobbit Theexpression ${foo:7}returns he_Hobbit, while ${foo:7:5}returns he_Ho These twooperators are best used when working with data that is in a known, and fixed, format(such as the output of the lscommand) Be aware, though, that ls’s output format varieswidely among the various UNIX-like operating systems, so this sort of shell code wouldnot be portable.
Pattern-Matching Operators
Pattern-matching operators are most useful for working with freely formatted strings orvariable-length records delimited by fixed characters The $PATHenvironment variable is
an example Although it can be quite long, the individual directories are colon-delimited
Table 34.3 lists bash’s pattern-matching operators and their function
${var#pattern} Deletes the shortest match of pattern from the front of
${var##pattern} Deletes the longest match of pattern from the front of
${var%pattern} Deletes the shortest match of pattern from the end of
${var%%pattern} Deletes the longest match of pattern from the end of
${var/pattern/string} Replaces the longest match of pattern in var with
string Replaces only the first match This operator is
${var//pattern/string} Replaces the longest match of pattern in var with
string Replaces all matches This operator is only
The canonical usage of bash’s pattern-matching operators is manipulating file and pathnames For example, suppose you have a shell variable named myfilethat has the value
/usr/src/linux/Documentation/ide.txt(which is the documentation for the kernel’sIDE disk driver) Using “/*”and “*/”as the pattern, you can emulate the behavior ofthe dirnameand basename commands, as the output from Listing 34.3 illustrates
Trang 29Listing 34.3 PATTERN-MATCHINGOPERATORS
8 echo ‘${myfile##*/}=’ ${myfile##*/}
9 echo ‘basename $myfile =’ $(basename $myfile)
10
11 echo ‘${myfile%/*}=’ ${myfile%/*}
12 echo ‘dirname $myfile =’ $(dirname $myfile)
Line 8 deletes the longest string matching “*/”in the filename, starting from the ning of the variable, which deletes everything through the final “/”, returning just thefilename Line 11 matches anything after “/”, starting from the end of the variable,which strips off just the filename and returns the path to the file The output of this scriptis:
begin-$ /pattern.sh
${myfile##*/} = ide.txt basename $myfile = ide.txt
${myfile%/*} = /usr/src/linux/Documentation dirname $myfile = /usr/src/linux/Documentation
To illustrate the pattern-matching and replacement operators, the following commandreplaces each colon in the $PATHenvironment variable with a new line, resulting in avery easy to read path display (this example will fail if you do not have bash2.0 ornewer):
$ echo -e ${PATH//:/\\n}
/usr/local/bin /bin
/usr/bin /usr/X11R6/bin
NOTE
The dirname command strips the non-directory suffix from a filename passed to
and basename have pathetic man pages, so if you want more information, you will have to read the info pages To quote their manual pages, “[t]he Texinfo documentation is now the authoritative source.”
Trang 30/home/kwall/bin /home/wall/wp/wpbin
Of course, your path statement will look somewhat different The -eargument to echo
tells it to interpret the \nas a new line rather than a literal string Perversely, however,you have to escape the escape (\\n) to get the new lines into the variable in order for
echoto interpret them
Flow Control
The few shell scripts presented so far have been fall-through scripts, lacking any controlstructures such as loops and conditionals Any programming language worth the namemust have facilities for repeating certain code blocks multiple times and for conditionallyexecuting, or not executing, other code blocks In this section, you will meet all of
bash’s flow-control structures, which include the following:
• if—Executes one or more statements if a condition is true or false
• for—Executes one or more statements a fixed number of times
• while—Executes one or more statements while a condition is true or false
• until—Executes one or more statements until a condition becomes true or false
• case—Executes one or more statements depending on the value of a variable
• select—Executes one or more statements based upon an option selected by a user
bashsupports conditional execution of code using the ifstatement, although its tion of the condition is slightly different from the behavior of the ifstatement of lan-guages like C or Pascal This peculiarity aside,bash’s ifstatement is just as fully featured as C’s Its syntax is summarized below
evalua-if condition then
statements [elif condition statements]
[else statements]
fi
First, be sure you understand that ifchecks the exit status of the last statement in
condition If it is 0(true), then statementswill be executed, but if it is non-zero,the else clause, if present, will be executed and control jumps to the first line of code fol-lowing fi The (optional) elifclause(s) (you can have as many as you like) will be
Trang 31executed only if the ifcondition is false Similarly, the (optional) elseclause will be
executed only if all else fails Generally, Linux programs return 0 on successful or
normal completion, and non-zero otherwise, so this limitation is not burdensome
WARNING
Not all programs follow the same standards for return values, so check the
to behave as expected, check the documented exit code.
Regardless of the way programs define their exit codes,bashtakes 0to mean true or mal and non-zero otherwise If you need specifically to check or save a command’s exitcode, use the $?operator immediately after running a command $?returns the exit code
nor-of the command most recently run
The matter becomes more complex because bash allows you to combine exit codes in
conditionusing the &&and ||operators, which approximately translate to logical AND
and logical OR Suppose that before you enter a code block, you have to change into adirectory and copy a file One way to accomplish this is to use nested ifs, such as in thefollowing code:
if cd /home/kwall/data then
if cp datafile datafile.bak then
# more code here fi
fi bash, however, allows you to write this much more concisely, as the following code snip-pet illustrates:
if cd /home/kwall/data && cp datafile datafile.bak then
# more code here fi
Both code snippets say the same thing, but the second one is much shorter and, in myopinion, much clearer and easier to follow If, for some reason, the cdcommand fails,
bashwill not attempt the copy operation
Trang 32Although ifonly evaluates exit codes, you can use the [ ]construct or the bash
built-in command,test, to evaluate more complex conditions [ condition ]returns a codethat indicates whether conditionis true or false testdoes the same thing, but I find itmore difficult to read
The range of available conditions that bashautomatically provides—currently 35—isrich and complete You can test a wide variety of file attributes and compare strings andintegers
The spaces after the opening bracket and before the closing bracket in
[ condition ] are required It is an annoying requirement of bash ’s shell
Table 34.4 lists the most common file test operators (the complete list can be obtainedfrom bashs excellent manual pages)
-d file file exists and is a directory
-e file file exists
-f file file exists and is a regular file (not a directory or special
tory, you have search permission on it
-O file You own file -G file file’ s group ownership matches one of your group mem-
berships
file1 -nt file2 file1 is newer than file2
Trang 33The sample shell script for the file test operators lists each directory in $PATHfollowed
by some of the attributes for each directory The code for this script,descpath.sh, ispresented in Listing 34.4:
/usr/local/bin You don’t have write permission in /usr/local/bin You don’t own /usr/local/bin
You aren’t a member of /usr/local/bin’s group /bin
You don’t have write permission in /bin You don’t own /bin
Trang 34You aren’t a member of /bin’s group /usr/bin
You don’t have write permission in /usr/bin You don’t own /usr/bin
You aren’t a member of /usr/bin’s group /usr/X11R6/bin
You don’t have write permission in /usr/X11R6/bin You don’t own /usr/X11R6/bin
You aren’t a member of /usr/X11R6/bin’s group /home/kwall/bin
You have write permission in /home/kwall/bin You own /home/kwall/bin
You are a member of /home/kwall/bin’s group /home/kwall/wp/wpbin
You have write permission in /home/kwall/wp/wpbin You own /home/kwall/wp/wpbin
You are a member of /home/kwall/wp/wpbin’s group bash’s string tests compare strings based on their lexicographic or dictionary order Thismeans, for example, that asis less than asd Table 34.5 lists the string tests
str1 = str2 str1 matches str2 str1 != str2 str1 does not match str2 str1 < str2 str1 is less than str2 str1 > str2 str1 is greater than str2 -n str str has length greater than 0 (is not null)
-z str str has length 0 (is null)
The integer tests behave as you might expect Table 34.6 lists these tests
Trang 35Determinate Loops: for
As Listing 34.4 showed,forallows you to execute a section of code a fixed number oftimes bash’s forconstruct, however, only allows you to iterate over a fixed list of valuesbecause it does not have a way to automatically increment or decrement a loop counter
in the manner of C, Pascal, or Basic Nevertheless, the forloop is a frequently used looptool because it operates neatly on lists, such as command-line parameters and lists offiles in a directory The complete syntax of foris as follows:
for value in list do
statements using $value done
listis a list of values, such as filenames valueis a single list item, and statementsare
bashexpressions that somehow use or manipulate value Linux, interestingly, lacks aconvenient way to rename groups of files Under MS-DOS, if you have 17 files eachwith a *.docextension, you can use the COPYcommand to copy each *.docfile to, say, a
*.txtfile The DOS command would be as follows:
C:\ copy doc\*.doc doc\*.txt
Use bash’s forloop to remedy this shortcoming The following code can be turned into
a shell script—helpfully named copy—that does precisely what you want:
for docfile in doc/*.doc do
cp $docfile ${docfile%.doc}.txt done
Using one of bash’s pattern-matching operators, this code snippet makes a copy of eachfile ending in a .docextension by replacing the .docat the end of the filename with
.txt
Where the forloop limits how many times a particular section of code will be executed,
bash’s whileand untilconstructs cause continued code execution while (as long as) oruntil a particular condition is met The only requirement is that either your code or theenvironment in which it is running must ensure that the condition in question is eventual-
ly met, or you will cause an infinite loop Their syntax is as follows:
while condition do
statements done
Trang 36This syntax means that as long as conditionremains true, execute statementsuntil
conditionbecomes false (until a program or command returns non-zero):
until condition do
statements done
In a way, the untilsyntax means the opposite of while’s: until conditionbecomes true,execute statements(that is, until a command or program returns a non-zero exit code,
do something else)
Experienced programmers will recognize that untilloops are an invitation to waiting,” which is poor programming practice and often a huge waste of resources,particularly CPU cycles On the other hand,bash’s whileconstruct gives you a way toovercome for’s inability automatically to increment or decrement a counter Imagine,for example, that your pointy-haired boss insists that you make 150 copies of a file Thefollowing sample snippet makes this possible (never mind that PHB is a moron):
“busy-declare -i idx idx=1
while [ $idx != 150 ] do
cp somefile somefile.$idx idx=$idx+1
done
In addition to illustrating the use of while, this code snippet also introduces the use of
bash’s integer arithmetic The declarestatement creates a variable,idx, defined as aninteger Each iteration of the loop increments idx, ensuring that the loop condition even-tually tests false and control exits the loop This script is on the CD-ROM as phb.sh Todelete the files it creates, execute rm somefile*
The next flow-control structure to consider is case, which behaves similarly to the
switchstatement in C: it allows you to execute blocks of code depending on the value of
a variable The complete syntax for caseis as follows:
case expr in pattern1 ) statements ;;
pattern2 ) statements ;;
Trang 37expris compared to each pattern, and the statements associated with the first match areexecuted ;;is the equivalent of a breakstatement in C, causing control to jump to thefirst line of code past esac Unlike C’s switchkeyword, however,bash’s casestatementallows you to test the value of expragainst patterns that can contain wildcard charac-ters.
Theselectcontrol structure (not available in bashversions earlier than 1.14) is unique
to the Korn and bashshells Additionally, it does not have an analogue in conventionalprogramming languages selectallows you to easily build simple menus and respond tothe user’s selection Its syntax is as follows:
select value [in list]
do statements that manipulate $value done
Listing 34.5 illustrates how selectworks
The script first sets the IFS character to:so that selectcan properly parse the $PATH
environment variable (line 6) Then, it changes the default prompt that selectuses, the
Trang 38built-in shell variable PS3, to something more helpful than #?(line 17) After clearing thescreen (line 10), it enters a loop, presenting a menu of directories derived from $PATH
and prompting the user to make a choice, as illustrated in Figure 34.1
If the user selects a valid choice, the command substitution on line 15 pipes the output ofthe lscommand through the word count command,wc, to count the number of files inthe directory and displays the result (lines 14-16) Because lscan be used with no argu-ments, the script first makes sure the $diris not null (if it were null,lswould operate
on the current directory even if the user selects an invalid menu choice) If the usermakes an invalid selection, line 18 displays an error message, followed by the prompt onhow to proceed on line 20 The readstatement, which I will cover later in the section
“Input and Output,” allows the user to view the output of line 16 (or 18) and patientlywaits for the user to press Enter to iterate through the loop again or to press Ctrl+C toquit
NOTE
As presented, the script loops infinitely if you do not press Ctrl+C However,
selection.
As befits a programming language,bashboasts a complete and capable array of control structures Although they behave in ways slightly different than do their ana-logues in conventional programming languages, they nevertheless enhance shell scriptswith considerable power and flexibility
Trang 39flow-Shell Functions
bash’s function feature, an expanded version of the function facility available in othershells, has two main advantages:
• Faster execution, because shell functions are already in memory
• Modularity, because functions help you generalize your shell scripts and allow abetter degree of organization
You can define shell functions using one of the following two forms:
function fname {
commands }
or
fname() { commands }
Either form is acceptable and there is no functional (pun intended) difference betweenthe two The usual convention is to define all of your functions at the beginning of ascript, before they are used, as I did in Listing 34.2 To call a function once it is defined,simply invoke the function name followed by any arguments it needs
It is worth making clear that, compared to C or Pascal,bash’s function interface is veryprimitive There is no error-checking and no method to pass arguments by value
However, as with C and Pascal, variables declared inside a function definition can bemade local to the function, thus avoiding namespace clashes by preceding the declaration
or first use of the variable with the keyword local, as illustrated in the following pet:
snip-function foo {
local myvar local yourvar=1 }
Because Listing 34.2 contains an example of the declaration and use of a shell function,you’re referred back to that script You might try changing the declaration form as anexperiment just to persuade yourself that the two forms are equivalent
Trang 40Input and Output
Due to space considerations, I will not cover all of bash’s input and output operators andfacilities Many of them deal with the arcana of file descriptors, I/O to- and from-devicefiles, and manipulating standard input and output The ones I will cover are a few I/Oredirectors and string I/O
I/O Redirectors
You have already seen the basic I/O redirectors,>and <, which redirect output and input,respectively The output redirector allows you to send the output from a command to afile For example the command:
$ cat $HOME/.bash_profile > out
creates a file named outin the current working directory containing the contents of your
bashinitialization file,.bash_profile, by redirecting cat’s output to that file
Similarly, you can provide the input to a command from a file or command using theinput redirector,< You can rewrite the previous catcommand to use input redirection, asshown in the following:
$ cat < $HOME/.bash_profile > out
The output of this command is the same, and also illustrates that you can redirect inputand output simultaneously
The output redirector,>, will overwrite any existing file Sometimes this is not what youwant, so bashprovides the append operator,>>, which adds data to the end of a file Thefollowing command adds the alias cdlputo the end of my .bashrcinitialization file:
$ echo “alias cdlpu=’cd $HOME/kwall/projects/lpu’”