Unix Shell Programming
Third Edition April 2005
ISBN 978-0-596-00965-6
Weitere Informationen zu diesem Buch
Inhaltsverzeichnis | Kolophon |
Inhaltsverzeichnis
- Chapter 1: bash Basics
- InhaltsvorschauSince the early 1970s, when it was first created, the UNIX operating system has become more and more popular. During this time it has branched out into different versions, and taken on such names as Ultrix, AIX, Xenix, SunOS, and Linux. Starting on minicomputers and mainframes, it has moved onto desktop workstations and even personal computers used at work and home. No longer a system used only by academics and computing wizards at universities and research centers, UNIX is used in many businesses, schools, and homes. As time goes on, more people will come into contact with UNIX.You may have used UNIX at your school, office, or home to run your applications, print documents, and read your electronic mail. But have you ever thought about the process that happens when you type a command and hit RETURN?Several layers of events take place whenever you enter a command, but we're going to consider only the top layer, known as the shell. Generically speaking, a shell is any user interface to the UNIX operating system, i.e., any program that takes input from the user, translates it into instructions that the operating system can understand, and conveys the operating system's output back to the user. Figure 1-1 shows the relationship between user, shell, and operating system.
Figure 1-1: The shell is a layer around the UNIX operating systemThere are various types of user interfaces. bash belongs to the most common category, known as character-based user interfaces. These interfaces accept lines of textual commands that the user types in; they usually produce text-based output. Other types of interfaces include the increasingly common graphical user interfaces (GUI), which add the ability to display arbitrary graphics (not just typewriter characters) and to accept input from a mouse or other pointing device, touch-screen interfaces (such as those on some bank teller machines), and so on.The shell's job, then, is to translate the user's command lines into operating system instructions. For example, consider this command line:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - What Is a Shell?
- InhaltsvorschauThe shell's job, then, is to translate the user's command lines into operating system instructions. For example, consider this command line:
sort -n phonelist > phonelist.sorted
This means, "Sort lines in the file phonelist in numerical order, and put the result in the file phonelist.sorted." Here's what the shell does with this command:- Breaks up the line into the pieces sort, -n, phonelist, >, and phonelist.sorted. These pieces are called words.
- Determines the purpose of the words: sort is a command, -n and phonelist are arguments, and > and phonelist.sorted, taken together, are I/O instructions.
- Sets up the I/O according to > phonelist.sorted (output to the file phone list.sorted) and some standard, implicit instructions.
- Finds the command sort in a file and runs it with the option -n (numerical order) and the argument phonelist (input filename).
Of course, each of these steps really involves several substeps, each of which includes a particular instruction to the underlying operating system.Remember that the shell itself is not UNIX—just the user interface to it. UNIX is one of the first operating systems to make the user interface independent of the operating system.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Scope of This Book
- InhaltsvorschauIn this book you will learn about bash, which is one of the most recent and powerful of the major UNIX shells. There are two ways to use bash: as a user interface and as a programming environment.This chapter and the next cover interactive use. These two chapters should give you enough background to use the shell confidently and productively for most of your everyday tasks.After you have been using the shell for a while, you will undoubtedly find certain characteristics of your environment (the shell's "look and feel") that you would like to change, and tasks that you would like to automate. Chapter 3 shows several ways of doing this.Chapter 3 also prepares you for shell programming, the bulk of which is covered in Chapter 4 through Chapter 6. You need not have any programming experience to understand these chapters and learn shell programming. Chapter 7 and Chapter 8 give more complete descriptions of the shell's I/O and process-handling capabilities, while Chapter 9 discusses various techniques for debugging shell programs.You'll learn a lot about bash in this book; you'll also learn about UNIX utilities and the way the UNIX operating system works in general. It's possible to become a virtuoso shell programmer without any previous programming experience. At the same time, we've carefully avoided going into excessive detail about UNIX internals. We maintain that you shouldn't have to be an internals expert to use and program the shell effectively, and we won't dwell on the few shell features that are intended specifically for low-level systems programmers.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- History of UNIX Shells
- InhaltsvorschauThe independence of the shell from the UNIX operating system per se has led to the development of dozens of shells throughout UNIX history—although only a few have achieved widespread use.The first major shell was the Bourne shell (named after its inventor, Steven Bourne); it was included in the first popular version of UNIX, Version 7, starting in 1979. The Bourne shell is known on the system as sh. Although UNIX has gone through many, many changes, the Bourne shell is still popular and essentially unchanged. Several UNIX utilities and administration features depend on it.The first widely used alternative shell was the C shell, or csh. This was written by Bill Joy at the University of California at Berkeley as part of the Berkeley Software Distribution (BSD) version of UNIX that came out a couple of years after Version 7.The C shell gets its name from the resemblance of its commands to statements in the C Programming Language, which makes the shell easier for programmers on UNIX systems to learn. It supports a number of operating system features (e.g., job control; see Chapter 8) that were unique to BSD UNIX but by now have migrated to most other modern versions. It also has a few important features (e.g., aliases; see Chapter 3) that make it easier to use in general.In recent years a number of other shells have become popular. The most notable of these is the Korn shell. This shell is a commercial product that incorporates the best features of the Bourne and C shells, plus many features of its own. The Korn shell is similar to bash in most respects; both have an abundance of features that make them easy to work with. The advantage of bash is that it is free. For further information on the Korn shell see Appendix A.The Bourne Again shell (named in punning tribute to Steve Bourne's shell) was created for use in the GNU project. The GNU project was started by Richard Stallman of the Free Software Foundation (FSF) for the purpose of creating a UNIX-compatible operating system and replacing all of the commercial UNIX utilities with freely distributable ones. GNU embodies not only new software utilities, but a new distribution concept: theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Getting bash
- InhaltsvorschauYou may or may not be using bash right now. Your system administrator probably set your account up with whatever shell he uses as the "standard" on the system. You may not even have been aware that there is more than one shell available.Yet it's easy for you to determine which shell you are using. Log in to your system and type echo $SHELL at the prompt. You will see a response containing sh, csh, ksh, or bash; these denote the Bourne, C, Korn, and bash shells, respectively. (There's also a chance that you're using another shell such as tcsh.)If you aren't using bash and you want to, then you first need to find out if it exists on your system. Just type bash. If you get a new prompt consisting of some information followed by a dollar sign (e.g., bash3 $ ), then all is well; type exit to go back to your normal shell.If you get a "not found" message, your system may not have it. Ask your system administrator or another knowledgeable user; there's a chance that you might have some version of bash installed on the system in a place (directory) that is not normally accessible to you. If not, read Chapter 11 to find out how you can obtain a version of bash.Once you know you have bash on your system, you can invoke it from whatever other shell you use by typing bash as above. However, it's much better to install it as your login shell, i.e., the shell that you get automatically whenever you log in. You may be able to do the installation by yourself. Here are instructions that are designed to work on the widest variety of UNIX systems. If something doesn't work (e.g., you type in a command and get a "not found" error message or a blank line as the response), you'll have to abort the process and see your system administrator. Alternatively, turn to Chapter 12 where we demonstrate a less straightforward way of replacing your current shell.You need to find out where bash is on your system, i.e., in which directory it's installed. You might be able to find the location by typingEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Interactive Shell Use
- InhaltsvorschauWhen you use the shell interactively, you engage in a login session that begins when you log in and ends when you type exit or logout or press CTRL-D. During a login session, you type in command lines to the shell; these are lines of text ending in RETURN that you type in to your terminal or workstation.By default, the shell prompts you for each command with an information string followed by a dollar sign, though as you will see in Chapter 3, the entire prompt can be changed.Shell command lines consist of one or more words, which are separated on a command line by blanks or TABs. The first word on the line is the command. The rest (if any) are arguments (also called parameters) to the command, which are names of things on which the command will act.For example, the command line lp myfile consists of the command lp (print a file) and the single argument myfile. lp treats myfile as the name of a file to print. Arguments are often names of files, but not necessarily: in the command line mail cam, the mail program treats cam as the username to which a message will be sent.An option is a special type of argument that gives the command specific information on what it is supposed to do. Options usually consist of a dash followed by a letter; we say "usually" because this is a convention rather than a hard-and-fast rule. The command lp -h myfile contains the option -h, which tells lp not to print the "banner page" before it prints the file.Sometimes options take their own arguments. For example, lp -d lp1 -h myfile has two options and one argument. The first option is -d lp1, which means "Send the output to the printer (destination) called lp1." The second option and argument are the same as in the previous example.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Files
- InhaltsvorschauAlthough arguments to commands aren't always files, files are the most important types of "things" on any UNIX system. A file can contain any kind of information, and indeed there are different types of files. Three types are by far the most important:
- Regular files
- Also called text files; these contain readable characters. For example, this book was created from several regular files that contain the text of the book plus human-readable formatting instructions to the troff word processor.
- Executable files
- Also called programs; these are invoked as commands. Some can't be read by humans; others—the shell scripts that we'll examine in this book—are just special text files. The shell itself is a (non-human-readable) executable file called bash.
- Directories
- These are like folders that contain other files—possibly other directories (called subdirectories).
Let's review the most important concepts about directories. The fact that directories can contain other directories leads to a hierarchical structure, more popularly known as a tree, for all files on a UNIX system.Figure 1-1 shows part of a typical directory tree; rectangles are directories and ovals are regular files.
Figure 1-2: A tree of directories and filesThe top of the tree is a directory called root that has no name on the system. All files can be named by expressing their location on the system relative to root; such names are built by listing all of the directory names (in order from root), separated by slashes (/), followed by the file's name. This way of naming files is called a full (or absolute) pathname.For example, say there is a file called aaiw that is in the directory book, which is in the directory cam, which is in the directory home, which is in the root directory. This file's full pathname is /home/cam/book/aaiw.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Input and Output
- InhaltsvorschauThe software field—really, any scientific field—tends to advance most quickly and impressively on those few occasions when someone (i.e., not a committee) comes up with an idea that is small in concept yet enormous in its implications. The standard input and output scheme of UNIX has to be on the short list of such ideas, along with such classic innovations as the LISP language, the relational data model, and object-oriented programming.The UNIX I/O scheme is based on two dazzlingly simple ideas. First, UNIX file I/O takes the form of arbitrarily long sequences of characters (bytes). In contrast, file systems of older vintage have more complicated I/O schemes (e.g., "block," "record," "card image," etc.). Second, everything on the system that produces or accepts data is treated as a file; this includes hardware devices like disk drives and terminals. Older systems treated every device differently. Both of these ideas have made systems programmers' lives much more pleasant.By convention, each UNIX program has a single way of accepting input called standard input, a single way of producing output called standard output, and a single way of producing error messages called standard error output, usually shortened to standard error. Of course, a program can have other input and output sources as well, as we will see in Chapter 7.Standard I/O was the first scheme of its kind that was designed specifically for interactive users at terminals, rather than the older batch style of use that usually involved decks of punch-cards. Since the UNIX shell provides the user interface, it should come as no surprise that standard I/O was designed to fit in very neatly with the shell.All shells handle standard I/O in basically the same way. Each program that you invoke has all three standard I/O channels set to your terminal or workstation, so that standard input is your keyboard, and standard output and error are your screen or window. For example, theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Background Jobs
- InhaltsvorschauPipes are actually a special case of a more general feature: doing more than one thing at a time. This is a capability that many other commercial operating systems don't have, because of the rigid limits that they tend to impose upon users. UNIX, on the other hand, was developed in a research lab and meant for internal use, so it does relatively little to impose limits on the resources available to users on a computer—as usual, leaning towards uncluttered simplicity rather than overcomplexity."Doing more than one thing at a time" means running more than one program at the same time. You do this when you invoke a pipeline; you can also do it by logging on to a UNIX system as many times simultaneously as you wish. (If you try that on an IBM's VM/CMS system, for example, you will get an obnoxious "already logged in" message.)The shell also lets you run more than one command at a time during a single login session. Normally, when you type a command and hit RETURN, the shell will let the command have control of your terminal until it is done; you can't type in further commands until the first one is done. But if you want to run a command that does not require user input and you want to do other things while the command is running, put an ampersand (&) after the command.This is called running the command in the background, and a command that runs in this way is called a background job; by contrast, a job run the normal way is called a foreground job. When you start a background job, you get your shell prompt back immediately, enabling you to enter other commands.The most obvious use for background jobs is programs that take a long time to run, such as sort or uncompress on large files. For example, assume you just got an enormous compressed file loaded into your directory from magnetic tape. Let's say the file is gcc.tar.Z, which is a compressed archive file that contains well over 10 MB of source code files.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Special Characters and Quoting
- InhaltsvorschauThe characters <, >, |, and & are four examples of special characters that have particular meanings to the shell. The wildcards we saw earlier in this chapter (*, ?, and [...]) are also special characters.Table 1-6 gives the meanings of all special characters within shell command lines only. Other characters have special meanings in specific situations, such as the regular expressions and string-handling operators that we'll see in Chapter 3 and Chapter 4.
Table 1-6: Special characters CharacterMeaningSee chapter~Home directoryChapter 1`Command substitution (archaic)Chapter 4#CommentChapter 4$Variable expressionChapter 3&Background jobChapter 1*String wildcardChapter 1(Start subshellChapter 8)End subshellChapter 8\Quote next characterChapter 1|PipeChapter 1[Start character-set wildcardChapter 1]End character-set wildcardChapter 1{Start command blockChapter 7}End command blockChapter 7;Shell command separatorChapter 3`Strong quoteChapter 1<">Weak quoteChapter 1<Input redirectChapter 1>Output redirectChapter 1/Pathname directory separatorChapter 1?Single-character wildcardChapter 1!Pipeline logical NOTChapter 5Sometimes you will want to use special characters literally, i.e., without their special meanings. This is called quoting. If you surround a string of characters with single quotation marks (or quotes), you strip all characters within the quotes of any special meaning they might have.The most obvious situation where you might need to quote a string is with the echo command, which just takes its arguments and prints them to the standard output. What is the point of this? As you will see in later chapters, the shell does quite a bit of processing on command lines—most of which involves some of the special characters listed in Table 1-6.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Help
- InhaltsvorschauA feature in bash that no other shell has is an online help system. The help command gives information on commands in bash. If you type help by itself, you'll get a list of the built-in shell commands along with their options.If you provide help with a shell command name it will give you a detailed description of the command:
$ help cd cd: cd [-L | -P] [dir] Change the current directory to DIR. The variable $HOME is the default DIR. The variable $CDPATH defines the search path for the directory containing DIR. Alternative directory names in CDPATH are separated by a colon (:). A null directory name is the same as the current directory, i.e. `.'. If DIR begins with a slash (/), then $CDPATH is not used. If the directory is not found, and the shell option `cdable_vars' is set, then try the word as a variable name. If that variable has a value, then cd to the value of that variable. The -P option says to use the physical directory structure instead of following symbolic links; the -L option forces symbolic links to be followed.You can also provide help with a partial name, in which case it will return details on all commands matching the partial name. For example, help re will provide details on read, readonly, and return. The partial name can also include wildcards. You'll need to quote the name to ensure that the wildcard is not expanded to a filename. So the last example is equivalent to help `re*', and help `re??' will only return details on read.Sometimes help will show more than a screenful of information and it will scroll the screen. You can use the more command to show one screenful at a time by typing help command | more.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 2: Command-Line Editing
- InhaltsvorschauIt's always possible to make mistakes when you type at a computer keyboard, but perhaps even more so when you are using a UNIX shell. UNIX shell syntax is powerful, yet terse, full of odd characters, and not particularly mnemonic, making it possible to construct command lines that are as cryptic as they are complex. The Bourne and C shells exacerbate this situation by giving you extremely limited ways of editing your command lines.In particular, there is no way to recall a previous command line so that you can fix a mistake. If you are an experienced Bourne shell user, undoubtedly you know the frustration of having to retype long command lines. You can use the BACKSPACE key to edit, but once you hit RETURN, it's gone forever!The C shell provided a small improvement via its history mechanism, which provides a few very awkward ways of editing previous commands. But there are more than a few people who have wondered, "Why can't I edit my UNIX command lines in the same way I can edit text with an editor?"This is exactly what bash allows you to do. It has editing modes that allow you to edit command lines with editing commands similar to those of the two most popular UNIX editors, vi and emacs. It also provides a much-extended analog to the C shell history mechanism called fc (for fix command) that, among other things, allows you to use your favorite editor directly for editing your command lines. To round things out, bash also provides the original C shell history mechanism.In this chapter, we will discuss the features that are common to all of bash's command-history facilities; after that, we will deal with each facility in detail. If you use either vi or emacs, you may wish to read the section on the emulation mode for only the one you use. If you use neither vi nor emacs, but are interested in learning one of the editing modes anyway, we suggest emacs-mode, because it is more of a natural extension of the minimal editing capability you get with the bare shell.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Enabling Command-Line Editing
- Inhaltsvorschaubash initially starts interactively with emacs-mode as the default (unless you have started bash with the -noediting option; see Chapter 10). There are two ways to enter either editing mode while in the shell. First, you can use the set command:
$ set -o emacsor:$ set -o viThe second way of selecting the editing mode is to set a readline variable in the file .inputrc. We will look at this method later in this chapter.You will find that the vi- and emacs-editing modes are good at emulating the basic commands of these editors, but not their advanced features; their main purpose is to let you transfer "keyboard habits" from your favorite editor to the shell. fc is quite a powerful facility; it is mainly meant to supplant C shell history and as an "escape hatch" for users of editors other than vi or emacs. Therefore the section on fc is mainly recommended to C shell users and those who don't use either standard editor.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The History List
- InhaltsvorschauAll of bash's command history facilities depend on a list that records commands as you type them into the shell. Whenever you log in or start another interactive shell, bash reads an initial history list from the file .bash_history in your home directory. From that point on, every bash interactive session maintains its own list of commands. When you exit from a shell, it saves the list in .bash_history. You can call this file whatever you like by setting the environment variable HISTFILE. We'll look more closely at HISTFILE and some other related command history variables in the next chapter.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- emacs Editing Mode
- InhaltsvorschauIf you are an emacs user, you will find it most useful to think of emacs editing mode as a simplified emacs with a single, one-line window. All of the basic commands are available for cursor motion, cut-and-paste, and search.emacs-mode uses control keys for the most basic editing functions. If you aren't familiar with emacs, you can think of these as extensions of the rudimentary "erase" character (usually BACKSPACE or DEL) that UNIX provides through its interface to users' terminals. For the sake of consistency, we'll assume your erase character is DEL from now on; if it is CTRL-H or something else, you will need to make a mental substitution. The most basic control-key commands are shown in Table 2-1. (Important: remember that typing CTRL-D when your command line is empty may log you off!) The basic keyboard habits of emacs-mode are easy to learn, but they do require that you assimilate a couple of concepts that are peculiar to the emacs editor.
Table 2-1: Basic emacs-mode commands CommandDescriptionCTRL-BMove backward one character (without deleting)CTRL-FMove forward one characterDELDelete one character backwardCTRL-DDelete one character forwardThe first of these is the use of CTRL-B and CTRL-F for backward and forward cursor motion. These keys have the advantage of being obvious mnemonics. You can also use the left and right cursor motion keys ("arrow" keys), but for the rest of this discussion we will use the control keys, as they work on all keyboards. In emacs-mode, the point (sometimes also called dot) is an imaginary place just to the left of the character the cursor is on. In the command descriptions in Table 2-1, some say "forward" while others say "backward." Think of forward as "to the right of point" and backward as "to the left of point."For example, let's say you type in a line and, instead of typing RETURN, you type CTRL-B and hold it down so that it repeats. The cursor will move to the left until it is over the first character on the line, like this:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - vi Editing Mode
- InhaltsvorschauLike emacs-mode, vi-mode essentially creates a one-line editing window into the history list. vi-mode is popular because vi is the most standard UNIX editor. But the function for which vi was designed, writing C programs, has different editing requirements from those of command interpreters. As a result, although it is possible to do complex things in vi with relatively few keystrokes, the relatively simple things you need to do in bash sometimes take too many keystrokes.Like vi, vi-mode has two modes of its own: input and control mode. The former is for typing commands (as in normal bash use); the latter is for moving around the command line and the history list. When you are in input mode, you can type commands in and hit RETURN to run them. In addition, you have minimal editing capabilities via control characters, which are summarized in Table 2-7
Table 2-7: Editing commands in vi input mode CommandDescriptionDELDelete previous characterCTRL-WErase previous word (i.e., erase until a blank)CTRL-VQuote the next characterESCEnter control mode (see below)Note that at least some of these—depending on which version of UNIX you have—are the same as the editing commands provided by UNIX through its terminal interface. vi-mode will use your "erase" character as the "delete previous character" key; usually it is set to DEL or CTRL-H (BACKSPACE). CTRL-V works the same way as in emacs-mode; it causes the next character to appear in the command line as is and lose its special meaning.Under normal circumstances, you just stay in input mode. But if you want to go back and make changes to your command line, or if you want to recall previous commands, you need to go into control mode. To do this, hit ESC.A full range of vi editing commands are available to you in control mode. The simplest of these move you around the command line and are summarized in Table 2-8. vi-mode contains two "word" concepts. The simplest is any sequence of non-blank characters; we'll call this aEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The fc Command
- Inhaltsvorschaufc is a built-in shell command that provides a superset of the C shell history mechanism. You can use it to examine the most recent commands you entered, to edit one or more commands with your favorite "real" editor, and to run old commands with changes without having to type the entire command in again. We'll look at each of these uses in turn.The -l option to fc lists previous commands. It takes arguments that refer to commands in the history list. Arguments can be numbers or alphanumeric strings; numbers refer to the commands in the history list, while strings refer to the most recent command beginning with the string. fc treats arguments in a rather complex way:
- If you give two arguments, they serve as the first and last commands to be shown.
- If you specify one number argument, only the command with that number is shown.
- With a single string argument, it searches for the most recent command starting with that string and shows you everything from that command to the most recent command.
- If you specify no arguments, you will see the last 16 commands you entered. bash also has a built-in command for displaying the history: history.
A few examples should make these options clearer. Let's say you logged in and entered these commands:ls -l more myfile vi myfile wc -l myfile pr myfile | lp -h
If you type fc -l with no arguments, you will see the above list with command numbers, as in:1 ls -l 2 more myfile 3 vi myfile 4 wc -l myfile 5 pr myfile | lp -h
Adding another option, -n, suppresses the line numbers. If you want to see only commands 2 through 4, type fc -l 2 4. If you want to see only the vi command, type fc -l 3. To see everything from the vi command up to the present, type fc -l v. Finally, if you want to see commands between more and wc, you can type fc -l m w, fc -l m 4Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - History Expansion
- InhaltsvorschauIf you are a C shell user, you may be familiar with the history expansion mechanism that it provides. bash provides a similar set of features. History expansion is a primitive way to recall and edit commands in the history list. The way to recall commands is by the use of event designators. Table 2-15 gives a complete list.
Table 2-15: Event designators CommandDescription!Start a history substitution!!Refers to the last command! nRefers to command line n!- nRefers to the current command line minus n! stringRefers to the most recent command starting with string!? string?Refers to the most recent command containing string; the ending ? is optional^ string1^string2Repeat the last command, replacing string1 with string2By far the most useful command is !!. Typing !! on the command line re-executes the last command. If you know the command number of a specific command, you can use the !n form, where n is the command number. Command numbers can be determined from the history command. Alternatively, you can re-execute the most recent command beginning with the specified string by using ! string.You might also find the last expansion in the table to be of some use if you've made a typing mistake. For example, you might have typed:$ cat through_the_loking_glass | grep Tweedledee > dee.listInstead of moving back to the line and changing loking to looking, you could just type ^lok^look. This will change the string lok to look and then execute the resulting command.It's also possible to refer to certain words in a previous command by the use of a word designator. Table 2-16 lists available designators. Note that when counting words, bash (like most UNIX programs) starts counting with zero, not with one.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - readline
- Inhaltsvorschaubash's command-line editing interface is readline. It is actually a library of software developed for the GNU project that can be used by applications requiring a text-based interface. It provides editing and text-manipulation features to make it easier for the user to enter and edit text. Just as importantly, it allows standardization, in terms of both key strokes and customization methods, across all applications that use it.readline provides default editing in either of two modes: vi or emacs. Both modes provide a subset of the editing commands found in the full editors. We've already looked at the command sets of these modes in the previous sections of this chapter. We'll now look at how you can make your own command sets.readline gives bash added flexibility compared to other shells because it can be customized through the use of key bindings, either from the command line or in a special startup file. You can also set readline variables. We'll see how you can set up readline using your own startup file now, and then go on to examine how the binding capability can be used from the command line.The default startup file is called .inputrc and must exist in your home directory if you wish to customize readline. You can change the default filename by setting the environment variable INPUTRC (see Chapter 3 for further information on environment variables).When bash starts up, it reads the startup file (if there is one) and any settings there come into effect. The startup file is just a sequence of lines that bind a keyname to a macro or readline function name. You can also place comments in the file by preceding any line with a #.You can use either an English name or a key escape sequence for the keyname. For example, to bind CTRL-T to the movement command for moving to the end of the current line, you could place Control-t: end-of-line in your .inputrc. If you wanted to use a key escape sequence you could have put "Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Keyboard Habits
- InhaltsvorschauIn this chapter we have seen that bash provides command-line editing with two modes: vi and emacs. You may be wondering why these two editors were chosen. The primary reason is because vi and emacs are the most widely used editors for UNIX. People who have used either editor will find familiar editing facilities.If you are not familiar with either of these editors, you should seriously consider adopting emacs-mode keyboard habits. Because it is based on control keys and doesn't require you to think in terms of a "command mode" and "insert mode," you will find emacs-mode easier to assimilate. Although the full emacs is an extremely powerful editor, its command structure lends itself very well to small subsetting: there are several "mini-emacs" editors floating around for UNIX, MS-DOS, and other systems.The same cannot be said for vi, because its command structure is really meant for use in a full-screen editor. vi is quite powerful too, in its way, but its power becomes evident only when it is used for purposes similar to that for which it was designed: editing source code in C and LISP. As mentioned earlier, a vi user has the power to move mountains in few keystrokes—but at the cost of being unable to do anything meaningful in very few keystrokes. Unfortunately, the latter is most desired in a command interpreter, especially nowadays when users are spending more time within applications and less time working with the shell. In short, if you don't already know vi, you will probably find its commands obscure and confusing.Both bash editing modes have quite a few commands; you will undoubtedly develop keyboard habits that include just a few of them. If you use emacs-mode and you aren't familiar with the full emacs, here is a subset that is easy to learn yet enables you to do just about anything:
- For cursor motion around a command line, stick to CTRL-A and CTRL-E for beginning and end of line, and CTRL-F and CTRL-B for moving around.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 3: Customizing Your Environment
- InhaltsvorschauAn environment is a collection of concepts that express the things a computer system or other set of tools does in terms designed to be understandable and coherent, and a look and feel that is comfortable. For example, your desk at work is an environment. Concepts involved in desk work usually include memos, phone calls, letters, forms, etc. The tools on or in your desk that you use to deal with these things include paper, staples, envelopes, pens, a telephone, a calculator, etc. Every one of these has a set of characteristics that express how you use it; such characteristics range from location on your desk or in a drawer (for simple tools) to more sophisticated things like which numbers the memory buttons on your phone are set to. Taken together, these characteristics make up your desk's look and feel.You customize the look and feel of your desk environment by putting pens where you can most easily reach them, programming your phone buttons, etc. In general, the more customization you have done, the more tailored to your personal needs—and therefore the more productive—your environment is.Similarly, UNIX shells present you with such concepts as files, directories, and standard input and output, while UNIX itself gives you tools to work with these, such as file manipulation commands, text editors, and print queues. Your UNIX environment's look and feel is determined by your keyboard and display, of course, but also by how you set up your directories, where you put each kind of file, and what names you give to files, directories, and commands. There are also more sophisticated ways of customizing your shell environment.This chapter will look at the four most important features that bash provides for customizing your environment.
- Special files
- The files .bash_profile, .bash_logout, and .bashrc that are read by bash when you log in and out or start a new shell.
- Aliases
- Synonyms for commands or command strings that you can define for convenience.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The .bash_profile, .bash_logout, and .bashrc Files
- InhaltsvorschauThree files in your home directory have a special meaning to bash, providing a way for you to set up your account environment automatically when you log in and when you invoke another bash shell, and allowing you to perform commands when you log out. These files may already exist in your home directory, depending on how your system administrator has set up your account. If they don't exist, your account is using only the default system file /etc/profile. You can easily create your own bash files using your favorite text editor. If you are unfamiliar with text editors available under UNIX, we suggest that you familiarize yourself with one of the better-known ones such as vi or emacs before proceeding further with the techniques described in this chapter.The most important bash file, .bash_profile, is read and the commands in it executed by bash every time you log in to the system. If you examine your .bash_profile you will probably see lines similar to:
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin SHELL=/bin/bash MANPATH=/usr/man:/usr/X11/man EDITOR=/usr/bin/vi PS1='\h:\w\$ ' PS2='> ' export EDITORThese lines define the basic environment for your login account. For the moment, it is probably best to leave these lines alone until you understand what they do. When editing your .bash_profile, just add your new lines after the existing ones.Note that whatever you add to your .bash_profile won't take effect until the file is re-read by logging out and then logging in again. Alternatively, you can also use the source command. For example:source .bash_profile
source executes the commands in the specified file, in this case .bash_profile, including any commands that you have added.bash allows two synonyms for .bash_profile: .bash_login, derived from the C shell's file named .login, and .profile, derived from the Bourne shell and Korn shell files named .profile. Only one of these three is read when you log in. IfEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Aliases
- InhaltsvorschauIf you have used UNIX for any length of time you will have noticed that there are many commands available and that some of them have cryptic names. Sometimes the commands you use the most have a string of options and arguments that need to be specified. Wouldn't it be nice if there was a feature that let you rename the commands or allowed you to type in something simple instead of half a dozen options? Fortunately, bash provides such a feature: the alias.Aliases can be defined on the command line, in your .bash_profile, or in your .bashrc, using this form:
alias name=command
This syntax specifies that name is an alias for command. Whenever you type name as a command, bash will substitute command in its place when it executes the line. Notice that there are no spaces on either side of the equal sign (=); this is the required syntax.There are a few basic ways to use an alias. The first, and simplest, is as a more mnemonic name for an existing command. Many commonly used UNIX commands have names that are poor mnemonics and are therefore excellent candidates for aliasing, the classic example being:alias search=grep
grep, the UNIX file-searching utility, was named as an acronym for something like "Generalized Regular Expression Parser." This acronym may mean something to a computer scientist, but not to the office administrator who has to find Fred in a list of phone numbers. If you have to find Fred and you have the word search defined as an alias for grep, you can type:$ search Fred phonelistSome people who aren't particularly good typists like to use aliases for typographical errors they make often. For example:alias emcas=emacs alias mali=mail alias gerp=grep
This can be handy, but we feel you're probably better off suffering with the error message and getting the correct spelling under your fingers. Another common way to use an alias is as a shorthand for a longer command string. For example, you may have a directory to which you need to go often. It's buried deep in your directory hierarchy, so you want to set up an alias that will allow you toEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Options
- InhaltsvorschauWhile aliases let you create convenient names for commands, they don't really let you change the shell's behavior. Options are one way of doing this. A shell option is a setting that is either "on" or "off." While several options relate to arcane shell features that are of interest only to programmers, those that we will cover here are of interest to all users.The basic commands that relate to options are set -o optionname and set +o optionname. You can change more than one option with the one set command by preceding each optionname with a -o or +o. The use of plus (+) and minus (-) signs is counterintuitive: the - turns the named option on, while the + turns it off. The reason for this incongruity is that the dash (-) is the conventional UNIX way of specifying options to a command, while the use of + is an afterthought.Most options also have one-letter abbreviations that can be used in lieu of the set -o command; for example, set -o noglob can be abbreviated set -f. These abbreviations are carryovers from the Bourne shell. Like several other "extra" bash features, they exist to ensure upward compatibility; otherwise, their use is not encouraged.Table 3-1 lists the options that are useful to general UNIX users. All of them are off by default except as noted.
Table 3-1: Basic shell options OptionDescriptionemacsEnters emacs editing mode (on by default)ignoreeofDoesn't allow use of a single CTRL-D to log off; use the exit command to log off immediately (this has the same effect as setting the shell variable IGNOREEOF=10)noclobberDoesn't allow output redirection (>) to overwrite an existing filenoglobDoesn't expand filename wildcards like * and ? (wildcard expansion is sometimes called globbing)nounsetIndicates an error when trying to use a variable that is undefinedEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Shell Variables
- InhaltsvorschauThere are several characteristics of your environment that you may want to customize but that cannot be expressed as an on/off choice. Characteristics of this type are specified in shell variables. Shell variables can specify everything from your prompt string to how often the shell checks for new mail.Like an alias, a shell variable is a name that has a value associated with it. bash keeps track of several built-in shell variables; shell programmers can add their own. By convention, built-in variables should have names in all capital letters. bash does, however, have two exceptions. The syntax for defining variables is somewhat similar to the syntax for aliases:
varname=value
There must be no space on either side of the equal sign, and if the value is more than one word, it must be surrounded by quotes. To use the value of a variable in a command, precede its name by a dollar sign ($).You can delete a variable with the command unset varname. Normally this isn't useful, since all variables that don't exist are assumed to be null, i.e., equal to the empty string "". But if you use the set option nounset, which causes the shell to indicate an error when it encounters an undefined variable, then you may be interested in unset.The easiest way to check a variable's value is to use the echo built-in command. All echo does is print its arguments, but not until the shell has evaluated them. This includes—among other things that will be discussed later—taking the values of variables and expanding filename wildcards. So, if the variable wonderland has the value alice, typing:$ echo "$wonderland"will cause the shell to simply print alice. If the variable is undefined, the shell will print a blank line. A more verbose way to do this is:$ echo "The value of \$ varname is \"$ varname \"."
The first dollar sign and the inner double quotes are backslash-escaped (i.e., preceded withEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Customization and Subprocesses
- InhaltsvorschauSome of the variables discussed above are used by commands you may run—as opposed to the shell itself—so that they can determine certain aspects of your environment. The majority, however, are not even known outside the shell.This dichotomy begs an important question: which shell "things" are known outside the shell, and which are only internal? This question is at the heart of many misunderstandings about the shell and shell programming. Before we answer, we'll ask it again in a more precise way: which shell "things" are known to subprocesses? Remember that whenever you enter a command, you are telling the shell to run that command in a subprocess; furthermore, some complex programs may start their own subprocesses.Now for the answer, which (like many UNIX concepts) is unfortunately not as simple as you might like. A few things are known to subprocesses, but the reverse is not true: subprocesses can never make these things known to the processes that created them.Which things are known depends on whether the subprocess in question is a bash program (see Chapter 4) or an interactive shell. If the subprocess is a bash program, then it's possible to propagate nearly every type of thing we've seen in this chapter—options and variables—plus a few we'll see later.By default, only one kind of thing is known to all kinds of subprocesses: a special class of shell variables called environment variables. Some of the built-in variables we have seen are actually environment variables: HOME, MAIL, PATH, and PWD.It should be clear why these and other variables need to be known by subprocesses. For example, text editors like vi and emacs need to know what kind of terminal you are using; the environment variable TERM is their way of determining this. As another example, most UNIX mail programs allow you to edit a message with your favorite text editor. How does mail know which editor to use? The value ofEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Customization Hints
- InhaltsvorschauYou should feel free to try any of the techniques presented in this chapter. The best strategy is to test something out by typing it into the shell during your login session; then if you decide you want to make it a permanent part of your environment, add it to your .bash_profile.A nice, painless way to add to your .bash_profile without going into a text editor makes use of the echo command and one of bash's editing modes. If you type a customization command in and later decide to add it to your .bash_profile, you can recall it via CTRL-P or CTRL-R (in emacs-mode) or j, -, or ? (vi-mode). Let's say the line is:
PS1="\u \!--> "
After you recall it, edit the line so that it is preceded by an echo command, surrounded by single quotes, and followed by an I/O redirector that (as you will see in Chapter 7) appends the output to ~/.bash_profile:$ echo 'PS1="\u \!--> " ' >> ~/.bash_profileRemember that the single quotes are important because they prevent the shell from trying to interpret things like dollar signs, double quotes, and exclamation points. Also make sure that you use a double right-caret (>>). A single one will overwrite the file rather than appending to it.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 4: Basic Shell Programming
- InhaltsvorschauIf you have become familiar with the customization techniques we presented in the previous chapter, you have probably run into various modifications to your environment that you want to make but can't—yet. Shell programming makes these possible.bash has some of the most advanced programming capabilities of any command interpreter of its type. Although its syntax is nowhere near as elegant or consistent as that of most conventional programming languages, its power and flexibility are comparable. In fact, bash can be used as a complete environment for writing software prototypes.Some aspects of bash programming are really extensions of the customization techniques we have already seen, while others resemble traditional programming language features. We have structured this chapter so that if you aren't a programmer, you can read this chapter and do quite a bit more than you could with the information in the previous chapter. Experience with a conventional programming language like Pascal or C is helpful (though not strictly necessary) for subsequent chapters. Throughout the rest of the book, we will encounter occasional programming problems, called tasks, whose solutions make use of the concepts we cover.A script (a file that contains shell commands) is a shell program. Your .bash_profile and environment files, discussed in the previous chapter, are shell scripts.You can create a script using the text editor of your choice. Once you have created one, there are two ways to run it. One, which we have already covered, is to type source scriptname. This causes the commands in the script to be read and run as if you typed them in.The second way to run a script is simply to type its name and hit RETURN, just as if you were invoking a built-in command. This, of course, is the more convenient way. This method makes the script look just like any other UNIX command, and in fact several "regular" commands are implemented as shell scripts (i.e., not as programs originally written in C or some other language), includingEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Shell Scripts and Functions
- InhaltsvorschauA script (a file that contains shell commands) is a shell program. Your .bash_profile and environment files, discussed in the previous chapter, are shell scripts.You can create a script using the text editor of your choice. Once you have created one, there are two ways to run it. One, which we have already covered, is to type source scriptname. This causes the commands in the script to be read and run as if you typed them in.The second way to run a script is simply to type its name and hit RETURN, just as if you were invoking a built-in command. This, of course, is the more convenient way. This method makes the script look just like any other UNIX command, and in fact several "regular" commands are implemented as shell scripts (i.e., not as programs originally written in C or some other language), including spell, man on some systems, and various commands for system administrators. The resulting lack of distinction between "user command files" and "built-in commands" is one factor in UNIX's extensibility and, hence, its favored status among programmers.You can run a script by typing its name only if the directory where the script is located is in your command search path, or . (the current directory) is part of your command search path, i.e., the script's directory path (as discussed in Chapter 3). If these aren't in your path, you must type ./scriptname, which is really the same thing as typing the script's absolute pathname (see Chapter 1).Before you can invoke the shell script by name, you must also give it "execute" permission. If you are familiar with the UNIX filesystem, you know that files have three types of permissions (read, write, and execute) and that those permissions apply to three categories of user (the file's owner, a group of users, and everyone else). Normally, when you create a file with a text editor, the file is set up with read and write permission for you and read-only permission for everyone else.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Shell Variables
- Inhaltsvorschaubash derives much of its programming functionality from shell variables. We've already seen the basics of variables. To recap briefly: they are named places to store data, usually in the form of character strings, and their values can be obtained by preceding their names with dollar signs ($). Certain variables, called environment variables, are conventionally named in all capital letters, and their values are made known (with the export statement) to subprocesses.If you are a programmer, you already know that just about every major programming language uses variables in some way; in fact, an important way of characterizing differences between languages is comparing their facilities for variables.The chief difference between bash's variable schema and those of conventional languages is that bash's places heavy emphasis on character strings. (Thus it has more in common with a special-purpose language like SNOBOL than a general-purpose one like Pascal.) This is also true of the Bourne shell and the C shell, but bash goes beyond them by having additional mechanisms for handling integers explicitly.As we have already seen, you can define values for variables with statements of the form varname=value, e.g.:
$ hatter=mad $ echo "$hatter" mad
The shell predefines some environment variables when you log in. There are other built-in variables that are vital to shell programming. We will look at a few of them now and save the others for later.The most important special, built-in variables are called positional parameters. These hold the command-line arguments to scripts when they are invoked. Positional parameters have the names 1, 2, 3, etc., meaning that their values are denoted by $1, $2, $3, etc. There is also a positional parameter 0, whose value is the name of the script (i.e., the command typed in to invoke it).Two special variables contain all of the positional parameters (except positional parameterEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - String Operators
- InhaltsvorschauThe curly-bracket syntax allows for the shell's string operators. String operators allow you to manipulate values of variables in various useful ways without having to write full-blown programs or resort to external UNIX utilities. You can do a lot with string-handling operators even if you haven't yet mastered the programming features we'll see in later chapters.In particular, string operators let you do the following:
- Ensure that variables exist (i.e., are defined and have non-null values)
- Set default values for variables
- Catch errors that result from variables not being set
- Remove portions of variables' values that match patterns
The basic idea behind the syntax of string operators is that special characters that denote operations are inserted between the variable's name and the right curly bracket. Any argument that the operator may need is inserted to the operator's right.The first group of string-handling operators tests for the existence of variables and allows substitutions of default values under certain conditions. These are listed in Table 4-1.Table 4-1: Substitution operators OperatorSubstitution${ varname :- word }If varname exists and isn't null, return its value; otherwise return word.Purpose: Returning a default value if the variable is undefined.Example: ${count:-0} evaluates to 0 if count is undefined.${ varname := word}If varname exists and isn't null, return its value; otherwise set it to word and then return its value. Positional and special parameters cannot be assigned this way.Purpose: Setting a variable to a default value if it is undefined.Example: ${count:=0} sets count to 0 if it is undefined.${ varname :? message }If varname exists and isn't null, return its value; otherwise printEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Command Substitution
- InhaltsvorschauFrom the discussion so far, we've seen two ways of getting values into variables: by assignment statements and by the user supplying them as command-line arguments (positional parameters). There is another way: command substitution, which allows you to use the standard output of a command as if it were the value of a variable. You will soon see how powerful this feature is.The syntax of command substitution is:
$(UNIX command)The command inside the parentheses is run, and anything the command writes to standard output is returned as the value of the expression. These constructs can be nested, i.e., the UNIX command can contain command substitutions.Here are some simple examples:- The value of $(pwd) is the current directory (same as the environment variable $PWD).
- The value of $(ls $HOME) is the names of all files in your home directory.
- The value of $(ls $(pwd)) is the names of all files in the current directory.
- The value of $(< alice) is the contents of the file alice with any trailing newlines removed.
- To find out detailed information about a command if you don't know where its file resides, type ls -l $(type -path -all command-name). The -all option forces type to do a pathname look-up and -path causes it to ignore keywords, built-ins, etc.
- If you want to edit (with vi) every chapter of your book on bash that has the phrase "command substitution," assuming that your chapter files all begin with ch, you could type:
vi $(grep -l 'command substitution' ch*)
- The -l option to grep prints only the names of files that contain matches.
Command substitution, like variable and tilde expansion, is done within double quotes. Therefore, our rule in Chapter 1 and Chapter 3 about using single quotes for strings unless they contain variables will now be extended: "When in doubt, use single quotes, unless the string contains variables or command substitutions, in which case use double quotes."Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Advanced Examples: pushd and popd
- InhaltsvorschauWe will conclude this chapter with a couple of functions that are already built into bash but are useful in demonstrating some of the concepts we have covered in this chapter.We will start by implementing a significant subset of their capabilities and finish the implementation in Chapter 6.Think of a stack as a spring-loaded dish receptacle in a cafeteria. When you place dishes on the receptacle, the spring compresses so that the top stays at roughly the same level. The dish most recently placed on the stack is the first to be taken when someone wants food; thus, the stack is known as a "last-in, first-out" or LIFO structure. Putting something onto a stack is known in computer science parlance as pushing, and taking something off the top is called popping.A stack is very handy for remembering directories, as we will see; it can "hold your place" up to an arbitrary number of times. The cd - form of the cd command does this, but only to one level. For example: if you are in firstdir and then you change to seconddir, you can type cd - to go back. But if you start out in firstdir, then change to seconddir, and then go to thirddir, you can use cd - only to go back to seconddir. If you type cd - again, you will be back in thirddir, because it is the previous directory.If you want the "nested" remember-and-change functionality that will take you back to firstdir, you need a stack of directories along with the pushd and popd commands. Here is how these work:
- The first time pushd dir is called, pushd pushes the current directory onto the stack, then cds to dir and pushes it onto the stack.
- Subsequent calls to pushd dir cd to dir and push dir only onto the stack.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 5: Flow Control
- InhaltsvorschauIf you are a programmer, you may have read the last chapter—with its claim at the outset that bash has an advanced set of programming capabilities—and wondered where many of the features from conventional languages were. Perhaps the most glaringly obvious "hole" in our coverage thus far concerns flow control constructs like if, for, while, and so on.Flow control gives a programmer the power to specify that only certain portions of a program run, or that certain portions run repeatedly, according to conditions such as the values of variables, whether or not commands execute properly, and others. We call this the ability to control the flow of a program's execution.Almost every shell script or function that's been shown thus far has had no flow control—they have just been lists of commands to be run! Yet bash, like the C and Bourne shells, has all of the flow control abilities you would expect and more; we will examine them in this chapter. We'll use them to enhance the solutions to some of the programming tasks we saw in the last chapter and to solve tasks that we will introduce here.Although we have attempted to explain flow control so that nonprogrammers can understand it, we also sympathize with programmers who dread having to slog through yet another tabula rasa explanation. For this reason, some of our discussions relate bash's flow-control mechanisms to those that programmers should know already. Therefore you will be in a better position to understand this chapter if you already have a basic knowledge of flow control concepts.bash supports the following flow control constructs:
- if/else
- Execute a list of statements if a certain condition is/is not true
- for
- Execute a list of statements a fixed number of times
- while
- Execute a list of statements repeatedly while a certain condition holds true
- until
- Execute a list of statements repeatedly until a certain condition holds true
- case
- Execute one of several lists of statements depending on the value of a variable
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - if/else
- InhaltsvorschauThe simplest type of flow control construct is the conditional, embodied in bash's if statement. You use a conditional when you want to choose whether or not to do something, or to choose among a small number of things to do, according to the truth or falsehood of conditions. Conditions test values of shell variables, characteristics of files, whether or not commands run successfully, and other factors. The shell has a large set of built-in tests that are relevant to the task of shell programming.The if construct has the following syntax:
if condition then statements [elif condition then statements...] [else statements] fi
The simplest form (without the elif and else parts, or clauses) executes the statements only if the condition is true. If you add an else clause, you get the ability to execute one set of statements if a condition is true or another set of statements if the condition is false. You can use as many elif (a contraction of "else if") clauses as you wish; they introduce more conditions, and thus more choices for which set of statements to execute. If you use one or more elifs, you can think of the else clause as the "if all else fails" part.Perhaps the only aspect of this syntax that differs from that of conventional languages like C and Pascal is that the "condition" is really a list of statements rather than the more usual Boolean (true or false) expression. How is the truth or falsehood of the condition determined? It has to do with a general UNIX concept that we haven't covered yet: the exit status of commands.Every UNIX command, whether it comes from source code in C, some other language, or a shell script/function, returns an integer code to its calling process—the shell in this case—when it finishes. This is called the exit status. 0 is usually the OK exit status, while anything else (1 to 255) usually denotes an error.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - for
- InhaltsvorschauThe most obvious enhancement to make the previous script is the ability to report on multiple files instead of just one. Tests like -e and -d take only single arguments, so we need a way of calling the code once for each file given on the command line.The way to do this—indeed, the way to do many things with bash—is with a looping construct. The simplest and most widely applicable of the shell's looping constructs is the for loop. We'll use for to enhance fileinfo soon.The for loop allows you to repeat a section of code a fixed number of times. During each time through the code (known as an iteration), a special variable called a loop variable is set to a different value; this way each iteration can do something slightly different.The for loop is somewhat, but not entirely, similar to its counterparts in conventional languages like C and Pascal. The chief difference is that the shell's standard for loop doesn't let you specify a number of times to iterate or a range of values over which to iterate; instead, it only lets you give a fixed list of values. In other words, you can't do anything like this Pascal-type code, which executes statements 10 times:
for x := 1 to 10 do begin statements... endHowever, the for loop is ideal for working with arguments on the command line and with sets of files (e.g., all files in a given directory). We'll look at an example of each of these. But first, we'll show the syntax for the for construct:for name [in list] do statements that can use $name... done
The list is a list of names. (If in list is omitted, the list defaults to "$@", i.e., the quoted list of command-line arguments, but we'll always supply the in list for the sake of clarity.) In our solutions to the following task, we'll show two simple ways to specify lists.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - case
- InhaltsvorschauThe next flow-control construct we will cover is case. While the case statement in Pascal and the similar switch statement in Java and C can be used to test simple values like integers and characters, bash's case construct lets you test strings against patterns that can contain wildcard characters. Like its conventional-language counterparts, case lets you express a series of if-then-else type statements in a concise way.The syntax of case is as follows:
case expression in pattern1 ) statements ;; pattern2 ) statements ;; ... esac
Any of the patterns can actually be several patterns separated by pipe characters (|). If expression matches one of the patterns, its corresponding statements are executed. If there are several patterns separated by pipe characters, the expression can match any of them in order for the associated statements to be run. The patterns are checked in order until a match is found; if none is found, nothing happens.This construct should become clearer with an example. Let's revisit our solution to Task 4-2 and the additions to it presented earlier in this chapter (our graphics utility). Remember that we wrote some code that processed input files according to their suffixes ( .pcx for PCX format, .gif for GIF format, etc.).We can improve upon this solution in two ways. Firstly, we can use a for loop to allow multiple files to be processed one at a time; secondly, we can use the case construct to streamline the code:for filename in "$@"; do pnmfile=${filename%.*}.ppm case $filename in *.jpg ) exit 0 ;; *.tga ) tgatoppm $filename > $pnmfile ;; *.xpm ) xpmtoppm $filename > $pnmfile ;; *.pcx ) pcxtoppm $filename > $pnmfile ;; *.tif ) tifftopnm $filename > $pnmfile ;; *.gif ) giftopnm $filename > $pnmfile ;; * ) echo "procfile: $filename is an unknown graphics file." exit 1 ;; esac outfile=${pnmfile%.ppm}.new.jpg pnmtojpeg $pnmfile > $outfile rm $pnmfile doneEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - select
- InhaltsvorschauAll of the flow-control constructs we have seen so far are also available in the Bourne shell, and the C shell has equivalents with different syntax. Our next construct, select, is available only in the Korn shell and bash; moreover, it has no analogy in conventional programming languages.select allows you to generate simple menus easily. It has concise syntax, but it does quite a lot of work. The syntax is:
select name [in list ] do statements that can use $name... done
This is the same syntax as for except for the keyword select. And like for, you can omit the in list and it will default to "$@", i.e., the list of quoted command-line arguments. Here is what select does:- Generates a menu of each item in list, formatted with numbers for each choice
- Prompts the user for a number
- Stores the selected choice in the variable name and the selected number in the built-in variable REPLY
- Executes the statements in the body
- Repeats the process forever (but see below for how to exit)
Here is a task that adds another command to our pushd and popd utilities.The display and selection of directories is best handled by using select. We can start off with something along the lines of:selectd ( ) { PS3='directory? ' select selection in $DIR_STACK; do if [ $selection ]; then #statements that manipulate the stack... break else echo 'invalid selection.' fi done }If you type DIR_STACK="/usr /home /bin" and execute this function, you'll see:1) /usr 2) /home 3) /bin directory?
The built-in shell variable PS3 contains the prompt string that select uses; its default value is the not particularly useful "Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - while and until
- InhaltsvorschauThe remaining two flow control constructs bash provides are while and until. These are similar; they both allow a section of code to be run repetitively while (or until) a certain condition becomes true. They also resemble analogous constructs in Pascal (while/do and repeat/until) and C (while and do/until).while and until are actually most useful when combined with features we will see in the next chapter, such as integer arithmetic, input/output of variables, and command-line processing. Yet we can show a useful example even with what we have covered so far.The syntax for while is:
while condition do statements... done
For until, just substitute until for while in the above example. As with if, the condition is really a list of statements that are run; the exit status of the last one is used as the value of the condition. You can use a conditional with test here, just as you can with if.Note that the only difference between while and until is the way the condition is handled. In while, the loop executes as long as the condition is true; in until, it runs as long as the condition is false. The until condition is checked at the top of the loop, not at the bottom as it is in analogous constructs in C and Pascal.The result is that you can convert any until into a while by simply negating the condition. The only place where until might be more meaningful is something like this:until command ; do statements... done
The meaning of this is essentially, "Do statements until command runs correctly." This is not a likely contingency.Here is an earlier task that can be rewritten using a while.We can use the while construct and pattern matching to traverse the PATH list:path=$PATH: while [ $path ]; do ls -ld ${path%%:*} path=${path#*:} doneThe first line copies PATH to a temporary copy,Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 6: Command-Line Options and Typed Variables
- InhaltsvorschauYou should have a healthy grasp of shell programming techniques now that you have gone through the previous chapters. What you have learned up to this point enables you to write many non-trivial, useful shell scripts and functions.Still, you may have noticed some remaining gaps in the knowledge you need to write shell code that behaves like the UNIX commands you are used to. In particular, if you are an experienced UNIX user, it might have occurred to you that none of the example scripts shown so far have the ability to handle options preceded by a dash (-) on the command line. And if you program in a conventional language like C or Pascal, you will have noticed that the only type of data that we have seen in shell variables is character strings; we haven't seen how to do arithmetic, for example.These capabilities are certainly crucial to the shell's ability to function as a useful UNIX programming language. In this chapter, we will show how bash supports these and related features.We have already seen many examples of the positional parameters (variables called 1, 2, 3, etc.) that the shell uses to store the command-line arguments to a shell script or function when it runs. We have also seen related variables like * (for the string of all arguments) and # (for the number of arguments).Indeed, these variables hold all of the information on the user's command-line. But consider what happens when options are involved. Typical UNIX commands have the form command [-options]args, meaning that there can be 0 or more options. If a shell script processes the command teatime alice hatter, then $1 is "alice" and $2 is "hatter". But if the command is teatime -o alice hatter, then $1 is -o, $2 is "alice", and $3 is "hatter".You might think you could write code like this to handle it:
if [ $1 = -o ]; then code that processes the -o option 1=$2 2=$3 fi normal processing of $1 and $2...But this code has several problems. First, assignments likeEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Command-Line Options
- InhaltsvorschauWe have already seen many examples of the positional parameters (variables called 1, 2, 3, etc.) that the shell uses to store the command-line arguments to a shell script or function when it runs. We have also seen related variables like * (for the string of all arguments) and # (for the number of arguments).Indeed, these variables hold all of the information on the user's command-line. But consider what happens when options are involved. Typical UNIX commands have the form command [-options]args, meaning that there can be 0 or more options. If a shell script processes the command teatime alice hatter, then $1 is "alice" and $2 is "hatter". But if the command is teatime -o alice hatter, then $1 is -o, $2 is "alice", and $3 is "hatter".You might think you could write code like this to handle it:
if [ $1 = -o ]; then code that processes the -o option 1=$2 2=$3 fi normal processing of $1 and $2...But this code has several problems. First, assignments like 1=$2 are illegal because positional parameters are read-only. Even if they were legal, another problem is that this kind of code imposes limitations on how many arguments the script can handle—which is very unwise. Furthermore, if this command had several possible options, the code to handle all of them would get very messy very quickly.Luckily, the shell provides a way around this problem. The command shift performs the function of:1=$2 2=$3 ...
for every argument, regardless of how many there are. If you supply a numeric argument to shift, it will shift the arguments that many times over; for example, shift 3 has this effect:1=$4 2=$5 ...
This leads immediately to some code that handles a single option (call it -o) and arbitrarily many arguments:if [ $1 = -o ]; then process the -o option shift fi normal processing of arguments...After the if construct, $1, $2, etc., are set to the correct arguments.We can use shiftEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Typed Variables
- InhaltsvorschauSo far we've seen how bash variables can be assigned textual values. Variables can also have other attributes, including being read only and being of type integer.You can set variable attributes with the declare built-in. Table 6-1 summarizes the available options with declare. A - turns the option on, while + turns it off.
Table 6-1: Declare options OptionMeaning-aThe variables are treated as arrays-fUse function names only-FDisplay function names without definitions-iThe variables are treated as integers-rMakes the variables read-only-xMarks the variables for export via the environmentTyping declare on its own displays the values of all variables in the environment. The -f option limits this display to the function names and definitions currently in the environment. -F limits it further by displaying only the function names.The -a option declares arrays—a variable type that we haven't seen yet, but will be discussed shortly.The -i option is used to create an integer variable, one that holds numeric values and can be used in and modified by arithmetic operations. Consider this example:$ val1=12 val2=5 $ result1=val*val2 $ echo $result1 val1*val2 $ $ declare -i val3=12 val4=5 $ declare -i result2 $ result2=val3*val4 $ echo $result2 60
In the first example, the variables are ordinary shell variables and the result is just the string "val1*val2". In the second example, all of the variables have been declared as type integer. The variable result contains the result of the arithmetic computation twelve multiplied by five. Actually, we didn't need to declare val3 and val4 as type integer. Anything being assigned to result2 is interpreted as an arithmetic statement and evaluation is attempted.The -x option to declare operates in the same way as the export built-in that we saw in Chapter 3. It allows the listed variables to be exported outside the current shell environment.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Integer Variables and Arithmetic
- InhaltsvorschauThe expression $(($OPTIND - 1)) in the last graphics utility example shows another way that the shell can do integer arithmetic. As you might guess, the shell interprets words surrounded by $(( and )) as arithmetic expressions. Variables in arithmetic expressions do not need to be preceded by dollar signs, though it is not wrong to do so.Arithmetic expressions are evaluated inside double quotes, like tildes, variables, and command substitutions. We're finally in a position to state the definitive rule about quoting strings: when in doubt, enclose a string in single quotes, unless it contains tildes or any expression involving a dollar sign, in which case you should use double quotes.For example, the date command on modern versions of UNIX accepts arguments that tell it how to format its output. The argument +%j tells it to print the day of the year, i.e., the number of days since December 31st of the previous year.We can use +%j to print a little holiday anticipation message:
echo "Only $(( (365-$(date +%j)) / 7 )) weeks until the New Year"
We'll show where this fits in the overall scheme of command-line processing in Chapter 7.The arithmetic expression feature is built into bash's syntax, and was available in the Bourne shell (most versions) only through the external command expr. Thus it is yet another example of a desirable feature provided by an external command being better integrated into the shell. getopts, as we have already seen, is another example of this design trend.bash arithmetic expressions are equivalent to their counterparts in the Java and C languages. Precedence and associativity are the same as in C. Table 6-2 shows the arithmetic operators that are supported. Although some of these are (or contain) special characters, there is no need to backslash-escape them, because they are within the $((...)) syntax.Table 6-2: Arithmetic operators Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Arrays
- InhaltsvorschauThe pushd and popd functions use a string variable to hold a list of directories and manipulate the list with the string pattern-matching operators. Although this is quite efficient for adding or retrieving items at the beginning or end of the string, it becomes cumbersome when attempting to access items that are anywhere else, e.g., obtaining item N with the getNdirs function. It would be nice to be able to specify the number, or index, of the item and retrieve it. Arrays allow us to do this.An array is like a series of slots that hold values. Each slot is known as an element, and each element can be accessed via a numerical index. An array element can contain a string or a number, and you can use it just like any other variable. The indices for arrays start at 0 and continue up to a very large number. So, for example, the fifth element of array names would be names[4]. Indices can be any valid arithmetic expression that evaluates to a number greater than or equal to 0.There are several ways to assign values to arrays. The most straightforward way is with an assignment, just like any other variable:
names[2]=alice names[0]=hatter names[1]=duchess
This assigns hatter to element 0, duchess to element 1, and alice to element 2 of the array names.Another way to assign values is with a compound assignment:names=([2]=alice [0]=hatter [1]=duchess)
This is equivalent to the first example and is convenient for initializing an array with a set of values. Notice that we didn't have to specify the indices in numerical order. In fact, we don't even have to supply the indices if we reorder our values slightly:names=(hatter duchess alice)
bash automatically assigns the values to consecutive elements starting at 0. If we provide an index at some point in the compound assignment, the values get assigned consecutively from that point on, so:names=(hatter [5]=duchess alice)
assigns hatter to element 0, duchess to element 5, and alice to elementEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 7: Input/Output and Command-Line Processing
- InhaltsvorschauThe past few chapters have gone into detail about various shell programming techniques, mostly focused on the flow of data and control through shell programs. In this chapter, we switch the focus to two related topics. The first is the shell's mechanisms for doing file-oriented input and output. We present information that expands on what you already know about the shell's basic I/O redirectors.Second, we'll "zoom in" and talk about I/O at the line and word level. This is a fundamentally different topic, since it involves moving information between the domains of files/terminals and shell variables. echo and command substitution are two ways of doing this that we've seen so far.Our discussion of line and word I/O will lead into a more detailed explanation of how the shell processes command lines. This information is necessary so that you can understand exactly how the shell deals with quotation, and so that you can appreciate the power of an advanced command called eval, which we will cover at the end of the chapter.In Chapter 1, you learned about the shell's basic I/O redirectors: >, <, and |. Although these are enough to get you through 95% of your UNIX life, you should know that bash supports many other redirectors. Table 7-1 lists them, including the three we've already seen. Although some of the rest are broadly useful, others are mainly for systems programmers.
Table 7-1: I/O redirectors RedirectorFunctioncmd1 | cmd2Pipe; take standard output of cmd1 as standard input to cmd2.> fileDirect standard output to file.< fileTake standard input from file.>> fileDirect standard output to file; append to file if it already exists.>| fileForce standard output to file even if noclobber is set.n>| fileForce output toEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - I/O Redirectors
- InhaltsvorschauIn Chapter 1, you learned about the shell's basic I/O redirectors: >, <, and |. Although these are enough to get you through 95% of your UNIX life, you should know that bash supports many other redirectors. Table 7-1 lists them, including the three we've already seen. Although some of the rest are broadly useful, others are mainly for systems programmers.
Table 7-1: I/O redirectors RedirectorFunctioncmd1 | cmd2Pipe; take standard output of cmd1 as standard input to cmd2.> fileDirect standard output to file.< fileTake standard input from file.>> fileDirect standard output to file; append to file if it already exists.>| fileForce standard output to file even if noclobber is set.n>| fileForce output to file from file descriptor n even if noclobber is set.<> fileUse file as both standard input and standard output.n<> fileUse file as both input and output for file descriptor n.<< labelHere-document; see text.n > fileDirect file descriptor n to file.n < fileTake file descriptor n from file.n >> fileDirect file descriptor n to file; append to file if it already exists.n>&Duplicate standard output to file descriptor n.n<&Duplicate standard input from file descriptor n.n>&mFile descriptor n is made to be a copy of the output file descriptor.n<&mFile descriptor n is made to be a copy of the input file descriptor.&>fileDirects standard output and standard error to file.<&-Close the standard input.>&-Close the standard output.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - String I/O
- InhaltsvorschauNow we'll zoom back in to the string I/O level and examine the echo and read statements, which give the shell I/O capabilities that are more analogous to those of conventional programming languages.As we've seen countless times in this book, echo simply prints its arguments to standard output. Now we'll explore the command in greater detail.
Section 7.2.1.1: Options to echo
echo accepts a few dash options, listed in Table 7-2.Table 7-2: echo options OptionFunction-eTurns on the interpretation of backslash-escaped characters-ETurns off the interpretation of backslash-escaped characters on systems where this mode is the default-nOmits the final newline (same as the \c escape sequence)Section 7.2.1.2: echo escape sequences
echo accepts a number of escape sequences that start with a backslash. They are listed in Table 7-3.These sequences exhibit fairly predictable behavior, except for \f: on some displays, it causes a screen clear, while on others it causes a line feed. It ejects the page on most printers. \v is somewhat obsolete; it usually causes a line feed.Table 7-3: echo escape sequences SequenceCharacter printed\aALERT or CTRL-G (bell)\bBACKSPACE or CTRL-H\cOmit final NEWLINE\eEscape character (same as \E)\EEscape character\fFORMFEED or CTRL-L\nNEWLINE (not at end of command) or CTRL-J\rRETURN (ENTER) or CTRL-M\tTAB or CTRL-I\vVERTICAL TAB or CTRL-K\ nASCII character with octal (base-8) value n, where n is 1 to 3 digits\0nnnThe eight-bit character whose value is the octal (base-8) value nnn where nnn is 1 to 3 digits\xHHThe eight-bit character whose value is the hexadecimal (base-16) value HH (one or two digits)\\Single backslashThe \n, \0, andEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Command-Line Processing
- InhaltsvorschauWe've seen how the shell uses read to process input lines: it deals with single quotes (`'), double quotes (""), and backslashes (\); it separates lines into words, according to delimiters in the environment variable IFS; and it assigns the words to shell variables. We can think of this process as a subset of the things the shell does when processing command lines.We've touched upon command-line processing throughout this book; now is a good time to make the whole thing explicit. Each line that the shell reads from the standard input or a script is called a pipeline; it contains one or more commands separated by zero or more pipe characters (|). For each pipeline it reads, the shell breaks it up into commands, sets up the I/O for the pipeline, then does the following for each command (Figure 7-1):
Figure 7-1: Steps in command-line processing- Splits the command into tokens that are separated by the fixed set of metacharacters: SPACE, TAB, NEWLINE, ;, (, ), <, >, |, and &. Types of tokens include words, keywords, I/O redirectors, and semicolons.
- Checks the first token of each command to see if it is a keyword with no quotes or backslashes. If it's an opening keyword, such as if and other control-structure openers, function, {, or (, then the command is actually a compound command. The shell sets things up internally for the compound command, reads the next command, and starts the process again. If the keyword isn't a compound command opener (e.g., is a control-structure "middle" like then, else, or do, an "end" like fi or done, or a logical operator), the shell signals a syntax error.
- Checks the first word of each command against the list of aliases. If a match is found, it substitutes the alias's definition and goes back to Step 1; otherwise, it goes on to Step 4. This scheme allows recursive aliases (see Chapter 3). It also allows aliases for keywords to be defined, e.g.,
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 8: Process Handling
- InhaltsvorschauThe UNIX operating system built its reputation on a small number of concepts, all of which are simple yet powerful. We've seen most of them by now: standard input/output, pipes, text-filtering utilities, the tree-structured file system, and so on. UNIX also gained notoriety as the first small-computer operating system to give each user control over more than one process. We call this capability user-controlled multitasking.You may not think that multitasking is a big deal. You're probably used to the idea of running a process in the background by putting an ampersand (&) at the end of the command line. You have also seen the idea of a subshell in Chapter 4, when we showed how shell scripts run.In this chapter, we will cover most of bash's features that relate to multitasking and process handling in general. We say "most" because some of these features are, like the file descriptors we saw in the previous chapter, of interest only to low-level systems programmers.We'll start out by looking at certain important primitives for identifying processes and for controlling them during login sessions and within shell scripts. Then we will move out to a higher-level perspective, looking at ways to get processes to communicate with each other. We'll look in more detail at concepts we've already seen, like pipes and subshells.Don't worry about getting bogged down in low-level technical details about UNIX. We will provide only the technical information that is necessary to explain higher-level features, plus a few other tidbits designed to pique your curiosity. If you are interested in finding out more about these areas, refer to your UNIX Programmer's Manual or a book on UNIX internals that pertains to your version of UNIX. You might also find UNIX Power Tools of value.We strongly recommend that you try out the examples in this chapter. The behavior of code that involves multiple processes is not as easy to understand on paper as most of the other examples in this book.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Process IDs and Job Numbers
- InhaltsvorschauUNIX gives all processes numbers, called process IDs, when they are created. You will notice that when you run a command in the background by appending & to it, the shell responds with a line that looks like this:
$ alice &[1] 93In this example, 93 is the process ID for the alice process. The [1] is a job number assigned by the shell (not the operating system). What's the difference? Job numbers refer to background processes that are currently running under your shell, while process IDs refer to all processes currently running on the entire system, for all users. The term job basically refers to a command line that was invoked from your shell.If you start up additional background jobs while the first one is still running, the shell will number them 2, 3, etc. For example:$ duchess &[2] 102 $ hatter &[3] 104
Clearly, 1, 2, and 3 are easier to remember than 93, 102, and 104!The shell includes job numbers in messages it prints when a background job completes:[1]+ Done alice
We'll explain what the plus sign means soon. If the job exits with non-zero status (see Chapter 5), the shell will indicate the exit status:[1]+ Exit 1 alice
The shell prints other types of messages when certain abnormal things happen to background jobs; we'll see these later in this chapter.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Job Control
- InhaltsvorschauWhy should you care about process IDs or job numbers? Actually, you could probably get along fine through your UNIX life without ever referring to process IDs (unless you use a windowing workstation—as we'll see soon). Job numbers are more important, however: you can use them with the shell commands for job control.You already know the most obvious way of controlling a job: create one in the background with &. Once a job is running in the background, you can let it run to completion, bring it into the foreground, or send it a message called a signal.The built-in command fg brings a background job into the foreground. Normally this means that the job will have control of your terminal or window and therefore will be able to accept your input. In other words, the job will begin to act as if you typed its command without the &.If you have only one background job running, you can use fg without arguments, and the shell will bring that job into the foreground. But if you have several jobs running in the background, the shell will pick the one that you put into the background most recently. If you want some other job put into the foreground, you need to use the job's command name, preceded by a percent sign (%), or you can use its job number, also preceded by %, or its process ID without a percent sign. If you don't remember which jobs are running, you can use the command jobs to list them.A few examples should make this clearer. Let's say you created three background jobs as above. Then if you type jobs, you will see this:
[1] Running alice & [2]- Running duchess & [3]+ Running hatter &
jobs has a few interesting options. jobs -l also lists process IDs:[1] 93 Running alice & [2]- 102 Running duchess & [3]+ 104 Running hatter &
The -p option tells jobs to listEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Signals
- InhaltsvorschauWe mentioned earlier that typing CTRL-Z to suspend a job is similar to typing CTRL-C to stop a job, except that you can resume the job later. They are actually similar in a deeper way: both are particular cases of the act of sending a signal to a process.A signal is a message that one process sends to another when some abnormal event takes place or when it wants the other process to do something. Most of the time, a process sends a signal to a subprocess it created. You're undoubtedly already comfortable with the idea that one process can communicate with another through an I/O pipeline; think of a signal as another way for processes to communicate with each other. (In fact, any textbook on operating systems will tell you that both are examples of the general concept of interprocess communication, or IPC.)Depending on the version of UNIX, there are two or three dozen types of signals, including a few that can be used for whatever purpose a programmer wishes. Signals have numbers (from 1 to the number of signals the system supports) and names; we'll use the latter. You can get a list of all the signals on your system, by name and number, by typing kill -l. Bear in mind, when you write shell code involving signals, that signal names are more portable to other versions of UNIX than signal numbers.When you type CTRL-C, you tell the shell to send the INT (for "interrupt") signal to the current job; CTRL-Z sends TSTP (on most systems, for "terminal stop"). You can also send the current job a QUIT signal by typing CTRL-\ (control-backslash); this is sort of like a "stronger" version of CTRL-C. You would normally use CTRL-\ when (and only when) CTRL-C doesn't work.As we'll see soon, there is also a "panic" signal called KILL that you can send to a process when even CTRL-\ doesn't work. But it isn't attached to any control key, which means that you can't use it to stop the currently running process. INT, TSTP, and QUIT are the only signals you can use with control keys.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- trap
- InhaltsvorschauWe've been discussing how signals affect the casual user; now let's talk a bit about how shell programmers can use them. We won't go into too much depth about this, because it's really the domain of systems programmers.We mentioned above that programs in general can be set up to Section 8.4 specific signals and process them in their own way. The trap built-in command lets you do this from within a shell script. trap is most important for "bullet-proofing" large shell programs so that they react appropriately to abnormal events—just as programs in any language should guard against invalid input. It's also important for certain systems programming tasks, as we'll see in the next chapter.The syntax of trap is:
trap cmd sig1 sig2 ...That is, when any of sig1, sig2, etc., are received, run cmd, then resume execution. After cmd finishes, the script resumes execution just after the command that was interrupted.Of course, cmd can be a script or function. The sigs can be specified by name or by number. You can also invoke trap without arguments, in which case the shell will print a list of any traps that have been set, using symbolic names for the signals.Here's a simple example that shows how trap works. Suppose we have a shell script called loop with this code:while true; do sleep 60 doneThis will just pause for 60 seconds (the sleep command) and repeat indefinitely. true is a "do-nothing" command whose exit status is always 0. Try typing in this script. Invoke it, let it run for a little while, then type CTRL-C (assuming that is your interrupt key). It should stop, and you should get your shell prompt back.Now insert this line at the beginning of the script:trap "echo 'You hit control-C!'" INT
Invoke the script again. Now hit CTRL-C. The odds are overwhelming that you are interrupting the sleep command (as opposed to true). You should see the message "You hit control-C!", and the script will not stop running; instead, theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Coroutines
- InhaltsvorschauWe've spent the last several pages on almost microscopic details of process behavior. Rather than continue our descent into the murky depths, we'll revert to a higher-level view of processes.Earlier in this chapter, we covered ways of controlling multiple simultaneous jobs within an interactive login session; now we'll consider multiple process control within shell programs. When two (or more) processes are explicitly programmed to run simultaneously and possibly communicate with each other, we call them coroutines.This is actually nothing new: a pipeline is an example of coroutines. The shell's pipeline construct encapsulates a fairly sophisticated set of rules about how processes interact with each other. If we take a closer look at these rules, we'll be better able to understand other ways of handling coroutines—most of which turn out to be simpler than pipelines.When you invoke a simple pipeline—say, ls | more—the shell invokes a series of UNIX primitive operations, or system calls. In effect, the shell tells UNIX to do the following things; in case you're interested, we include in parentheses the actual system call used at each step:
- Create two subprocesses, which we'll call P1 and P2 (the fork system call).
- Set up I/O between the processes so that P1's standard output feeds into P2's standard input (pipe).
- Start /bin/ls in process P1 (exec).
- Start /bin/more in process P2 (exec).
- Wait for both processes to finish (wait).
You can probably imagine how the above steps change when the pipeline involves more than two processes.Now let's make things simpler. We'll see how to get multiple processes to run at the same time if the processes do not need to communicate. For example, we want the processes alice and hatter to run as coroutines, without communication, in a shell script. Our initial solution would be this:alice & hatter
Assume for the moment that hatter is the last command in the script. The above will work—but only ifEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Subshells
- InhaltsvorschauTo conclude this chapter, we will look at a simple type of interprocess relationship: that of a subshell with its parent shell. We saw in Chapter 3 that whenever you run a shell script, you actually invoke another copy of the shell that is a subprocess of the main, or parent, shell process. Now let's look at subshells in more detail.The most important things you need to know about subshells are what characteristics they get, or inherit, from their parents. These are as follows:
- The current directory
- Environment variables
- Standard input, output, and error, plus any other open file descriptors
- Signals that are ignored
Just as important are the things that a subshell does not inherit from its parent:- Shell variables, except environment variables and those defined in the environment file (usually .bashrc)
- Handling of signals that are not ignored
We covered some of this in Chapter 3, but these points are common sources of confusion, so they bear repeating.Subshells need not be in separate scripts; you can also start a subshell within the same script (or function) as the parent. You do this in a manner very similar to the command blocks we saw in the last chapter. Just surround some shell code with parentheses (instead of curly brackets), and that code will run in a subshell. We'll call this a nested subshell.For example, here is the calculator program from the last chapter, with a subshell instead of a command block:( while read line; do echo "$(alg2rpn $line)" done ) | dcThe code inside the parentheses will run as a separate process. This is usually less efficient than a command block. The differences in functionality between subshells and command blocks are very few; they primarily pertain to issues of scope, i.e., the domains in which definitions of things like shell variables and signal traps are known. First, code inside a nested subshell obeys the above rules of subshell inheritance, except that it knows about variables defined in the surrounding shell; in contrast, think of blocks as code units that inheritEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Process Substitution
- InhaltsvorschauA unique but rarely used feature of bash is process substitution. Let's say that you had two versions of a program that produced large quantities of output. You want to see the differences between the output from each version. You could run the two programs, redirecting their output to files, and then use the cmp utility to see what the differences were.Another way would be to use process substitution. There are two forms of this substitution. One is for input to a process: >(list); the other is for output from a process: <(list). list is a process that has its input or output connected to something via a named pipe. A named pipe is simply a temporary file that acts like a pipe with a name.In our case, we could connect the outputs of the two programs to the input of cmp via named pipes:
cmp <(prog1) <(prog2)
prog1 and prog2 are run concurrently and connect their outputs to named pipes. cmp reads from each of the pipes and compares the information, printing any differences as it does so.This chapter has covered a lot of territory. Here are some exercises that should help you make sure you have a firm grasp on the material. Don't worry if you have trouble with the last one; it's especially difficult.- Write a shell script called pinfo that combines the jobs and ps commands by printing a list of jobs with their job numbers, corresponding process IDs, running times, and full commands.
- Take a non-trivial shell script and "bullet-proof" it with signal traps.
- Take a non-trivial shell script and parallelize it as much as possible.
- Write the code that checks for duplicate arguments to the mcp script. Bear in mind that different pathnames can point to the same file. (Hint: if $i is "1", then eval `echo \${$i}' prints the first command-line argument. Make sure you understand why.)
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 9: Debugging Shell Programs
- InhaltsvorschauWe hope that we have convinced you that bash can be used as a serious UNIX programming environment. It certainly has enough features, control structures, etc. But another essential part of a programming environment is a set of powerful, integrated support tools. For example, there is a wide assortment of screen editors, compilers, debuggers, profilers, cross-referencers, etc., for languages like C and C++. If you program in one of these languages, you probably take such tools for granted, and you would undoubtedly cringe at the thought of having to develop code with, say, the ed editor and the adb machine-language debugger.But what about programming support tools for bash? Of course, you can use any editor you like, including vi and emacs. And because the shell is an interpreted language, you don't need a compiler. But there are no other tools available.This chapter looks at some useful features that you can use to debug shell programs. We'll look at how you can utilize them in the first part of this chapter. We'll then look at some powerful new features of bash, not present in most Bourne shell workalikes, which will help in building a shell script debugging tool. At the end of the chapter, we'll show step by step how to build a debugger for bash. The debugger, called bashdb, is a basic yet functional program that will not only serve as an extended example of various shell programming techniques, but will also provide you with a useful tool for examining the workings of your own shell scripts.What sort of functionality do you need to debug a program? At the most empirical level, you need a way of determining what is causing your program to behave badly, and where the problem is in the code. You usually start with an obvious what (such as an error message, inappropriate output, infinite loop, etc.), try to work backwards until you find a what that is closer to the actual problem (e.g., a variable with a bad value, a bad option to a command), and eventually arrive at the exactEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Basic Debugging Aids
- InhaltsvorschauWhat sort of functionality do you need to debug a program? At the most empirical level, you need a way of determining what is causing your program to behave badly, and where the problem is in the code. You usually start with an obvious what (such as an error message, inappropriate output, infinite loop, etc.), try to work backwards until you find a what that is closer to the actual problem (e.g., a variable with a bad value, a bad option to a command), and eventually arrive at the exact where in your program. Then you can worry about how to fix it.Notice that these steps represent a process of starting with obvious information and ending up with often obscure facts gleaned through deduction and intuition. Debugging aids make it easier to deduce and intuit by providing relevant information easily or even automatically, preferably without modifying your code.The simplest debugging aid (for any language) is the output statement, echo, in the shell's case. Indeed, old-time programmers debugged their FORTRAN code by inserting WRITE cards into their decks. You can debug by putting lots of echo statements in your code (and removing them later), but you will have to spend lots of time narrowing down not only what exact information you want but also where you need to see it. You will also probably have to wade through lots and lots of output to find the information you really want.Luckily, the shell has a few basic features that give you debugging functionality beyond that of echo. The most basic of these are options to the set -o command (as covered in Chapter 3). These options can also be used on the command line when running a script, as Table 9-1 shows.
Table 9-1: Debugging options set -o optionCommand-line optionActionnoexec-nDon't run commands; check for syntax errors onlyverbose-vEcho commands before running themxtrace-xEcho commands after command-line processingEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - A bash Debugger
- InhaltsvorschauIn this section we'll develop a very basic debugger for bash. Most debuggers have numerous sophisticated features that help a programmer in dissecting a program, but just about all of them include the ability to step through a running program, stop it at selected places, and examine the values of variables. These simple features are what we will concentrate on providing in our debugger. Specifically, we'll provide the ability to:
- Specify places in the program at which to stop execution. These are called breakpoints.
- Execute a specified number of statements in the program. This is called stepping.
- Examine and change the state of the program during its execution. This includes being able to print out the values of variables and change them when the program is stopped at a breakpoint or after stepping.
- Print out the source code we are debugging along with indications of where breakpoints are and what line in the program we are currently executing.
- Provide the debugging capability without having to change the original source code of the program we wish to debug in any way.
As you will see, the capability to do all of these things (and more) is easily provided by the constructs and methods we have seen in previous chapters.The bashdb debugger works by taking a shell script and turning it into a debugger for itself. It does this by concatenating debugger functionality and the target script, which we'll call the guinea pig script, and storing it in another file that then gets executed. The process is transparent to users—they will be unaware that the code that is executing is actually a modified copy of their script.The bash debugger has three main sections: the driver, the preamble, and the debugger functions.Section 9.2.1.1: The driver script
The driver script is responsible for setting everything up. It is a script called bashdb and looks like this:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 10: bash Administration
- InhaltsvorschauThere are two areas in which system administrators use the shell as part of their job: setting up a generic environment for users and for system security. In this chapter, we'll discuss bash's features that relate to these tasks. We assume that you already know the basics of UNIX system administration.As a prelude to system-wide customization, we want to emphasize that bash can be installed as if it were the standard Bourne shell, /bin/sh. Indeed, some systems, such as Linux, come with bash installed instead of the Bourne shell.If you want to do this with your system, you can just save the original Bourne shell to another filename (in case someone needs to use it) and either install bash as sh in the /bin directory, or better yet install bash in the /bin directory and create a symbolic link from /bin/sh to /bin/bash using the command ln -s /bin/bash /bin/sh. The reason we think that the second option is better is because bash changes its behavior slightly if started as sh, as we will see shortly.As detailed in Appendix A, bash is backward-compatible with the Bourne shell, except that it doesn't support ^ as a synonym for the pipe character (|). Unless you have an ancient UNIX system, or you have some very, very old shell scripts, you needn't worry about this.But if you want to be absolutely sure, simply search through all shell scripts in all directories in your PATH. An easy way to perform the search is to use the file command, which we saw in Chapter 5 and Chapter 9. file prints "executable shell script" when given the name of one. Here is a script that looks for ^ in shell scripts in every directory in your PATH:
IFS=: for d in $PATH; do echo checking $d: cd $d scripts=$(file * | grep 'shell script' | cut -d: -f1) for f in $scripts; do grep '\^' $f /dev/null done doneThe first line of this script makes it possible to use $PATH as an item list in the for loop. For each directory, itEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Installing bash as the Standard Shell
- InhaltsvorschauAs a prelude to system-wide customization, we want to emphasize that bash can be installed as if it were the standard Bourne shell, /bin/sh. Indeed, some systems, such as Linux, come with bash installed instead of the Bourne shell.If you want to do this with your system, you can just save the original Bourne shell to another filename (in case someone needs to use it) and either install bash as sh in the /bin directory, or better yet install bash in the /bin directory and create a symbolic link from /bin/sh to /bin/bash using the command ln -s /bin/bash /bin/sh. The reason we think that the second option is better is because bash changes its behavior slightly if started as sh, as we will see shortly.As detailed in Appendix A, bash is backward-compatible with the Bourne shell, except that it doesn't support ^ as a synonym for the pipe character (|). Unless you have an ancient UNIX system, or you have some very, very old shell scripts, you needn't worry about this.But if you want to be absolutely sure, simply search through all shell scripts in all directories in your PATH. An easy way to perform the search is to use the file command, which we saw in Chapter 5 and Chapter 9. file prints "executable shell script" when given the name of one. Here is a script that looks for ^ in shell scripts in every directory in your PATH:
IFS=: for d in $PATH; do echo checking $d: cd $d scripts=$(file * | grep 'shell script' | cut -d: -f1) for f in $scripts; do grep '\^' $f /dev/null done doneThe first line of this script makes it possible to use $PATH as an item list in the for loop. For each directory, it cds there and finds all shell scripts by piping the file command into grep and then, to extract the filename only, into cut. Then for each shell script, it searches for the ^ character.If you run this script, you will probably find several occurrences of ^—but these carets should be used within regular expressions inEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Environment Customization
- InhaltsvorschauLike the Bourne shell, bash uses the file /etc/profile for system-wide customization. When a user logs in, the shell reads and runs /etc/profile before running the user's .bash_profile.We won't cover all the possible commands you might want to put in /etc/profile. But bash has a few unique features that are particularly relevant to system-wide customization; we'll discuss them here.We'll start with two built-in commands that you can use in /etc/profile to tailor your users' environments and constrain their use of system resources. Users can also use these commands in their .bash_profile, or at any other time, to override the default settings.umask, like the same command in most other shells, lets you specify the default permissions that files have when users create them. It takes the same types of arguments that the chmod command does, i.e., absolute (octal numbers) or symbolic permission values.The umask contains the permissions that are turned off by default whenever a process creates a file, regardless of what permission the process specifies.We'll use octal notation to show how this works. As you probably know, the digits in a permission number stand (left to right) for the permissions of the owner, owner's group, and all other users, respectively. Each digit, in turn, consists of three bits, which specify read, write, and execute permissions from left to right. (If a file is a directory, the "execute" permission becomes "search" permission, i.e., permission to cd to it, list its files, etc.)For example, the octal number 640 equals the binary number 110 100 000. If a file has this permission, then its owner can read and write it; users in the owner's group can only read it; everyone else has no permission on it. A file with permission 755 gives its owner the right to read, write, and execute it and everyone else the right to read and execute (but not write).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- System Security Features
- InhaltsvorschauUNIX security is a problem of legendary notoriety. Just about every aspect of a UNIX system has some security issue associated with it, and it's usually the system administrator's job to worry about this issue.bash has two features that help solve this problem: the restricted shell, which is intentionally "brain damaged," and privileged mode, which is used with shell scripts that run as if the user were root.The restricted shell is designed to put the user into an environment where her ability to move around and write files is severely limited. It's usually used for "guest" accounts. You can make a user's login shell restricted by putting rbash in the user's /etc/passwd entry.The specific constraints imposed by the restricted shell disallow the user from doing the following:
- Changing working directories: cd is inoperative. If you try to use it, you will get the error message bash: cd: restricted.
- Redirecting output to a file: the redirectors >, >|, <>, and >> are not allowed.
- Assigning a new value to the environment variables ENV, BASH_ENV, SHELL, or PATH.
- Specifying any commands with slashes (/) in them. The shell will treat files outside of the current directory as "not found."
- Using the exec built-in.
- Specifying a filename containing a / as an argument to the . built-in command.
- Importing function definitions from the shell environment at startup.
- Adding or deleting built-in commands with the -f and -d options to the enable built-in command.
- Specifying the -p option to the builtin command.
- Turning off restricted mode with set +r.
These restrictions go into effect after the user's .bash_profile and environment files are run. In addition, it is wise to change the owner of the users' .bash_profile and .bashrc to root, and make these files read-only. The users' home directory should also be made read-only.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 11: Shell Scripting
- InhaltsvorschauFor the majority of this book, we've looked at the various elements that make up bash and how you can use them in writing shell scripts. If you've used other programming languages you will know that there is a difference between writing a piece of code that gets a job done and writing a piece of code that does the job but is also maintainable and conforms to what we could call "good practice."This chapter will give a brief introduction to some aspects of good practice and writing maintainable shell scripts along with helpful tips and tricks that you can use to make writing scripts easier.Six months ago you coded up a 100 line shell script. It made perfect sense then, but now you look at it and wonder, "Just what does that do?" This is a common pitfall among programmers—especially those writing in a shell language. Unfortunately, shells have developed with more than their fair share of obscure punctuation. This is a blessing for keeping typing to a minimum but doesn't help readability. It's important to make your code as readable as possible.The first rule of shell scripting is to comment your code. You should do this right from the start, even if the script is only a couple of lines long. Shell scripts have a habit of growing from a couple of lines to many hundreds of lines as more features are added, so it's best to get into the habit of commenting your code right at the beginning.To start with, consider having a main header or banner for your scripts. The information in the header should, at a minimum, say what the script does. Here is an example of a script header:
#!/bin/bash ##################################################### # Name: graphconv.sh # # Converts graphics files from one format to another. # # Usage: graphconv.sh <input-file> <output-file> # # Author: C. Newham # Date: 2004/12/02 #####################################################
This main header gives the name of the script, a brief summary of what it does, usage information, the name of the author, and when the script was written.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - What's That Do?
- InhaltsvorschauSix months ago you coded up a 100 line shell script. It made perfect sense then, but now you look at it and wonder, "Just what does that do?" This is a common pitfall among programmers—especially those writing in a shell language. Unfortunately, shells have developed with more than their fair share of obscure punctuation. This is a blessing for keeping typing to a minimum but doesn't help readability. It's important to make your code as readable as possible.The first rule of shell scripting is to comment your code. You should do this right from the start, even if the script is only a couple of lines long. Shell scripts have a habit of growing from a couple of lines to many hundreds of lines as more features are added, so it's best to get into the habit of commenting your code right at the beginning.To start with, consider having a main header or banner for your scripts. The information in the header should, at a minimum, say what the script does. Here is an example of a script header:
#!/bin/bash ##################################################### # Name: graphconv.sh # # Converts graphics files from one format to another. # # Usage: graphconv.sh <input-file> <output-file> # # Author: C. Newham # Date: 2004/12/02 #####################################################
This main header gives the name of the script, a brief summary of what it does, usage information, the name of the author, and when the script was written.If you are using a source control system (e.g., CVS), you can dispense with the author and date as these will be stored when the script is archived. If you aren't using such a system, we strongly advise that you not only include the above information but also place in the header additional data such as modification dates and authors.Whatever system you use, make sure that you make the format of the banner a standard across all of your scripts.Every function should also have a header. If it is a standalone function, it should have a main header, as given above. If it is a function used locally in a script, it should have a simpler banner stating what it does, what parameters it expects, and what it returns, e.g.:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Starting Up
- InhaltsvorschauIn Chapter 6 we talked about using getopts to obtain options and arguments passed in to a shell script. This command makes it easy for the script programmer to process what the user has provided, but what about the other half of the deal? The programmer must make an effort to make life as easy for the user as possible. Nothing makes a user more irate than a script that doesn't take standard arguments, doesn't provide a usage message, doesn't process the arguments in the expected way, and forces the user into a way of thinking that the programmer thinks is the right way. Having to examine the source code for a script to find out what is an acceptable argument or option is usually the last straw!The Free Software Foundation has published a set of guidelines for writing GNU software that suggests standard ways in which UNIX utilities should operate. When writing your own shell scripts, it is worthwhile to follow the guidelines because your script will then look familiar to users who have used other command-line programs.At a minimum your script should provide single letter options (such as -h) and long options with the double dash (such as —help). It should also provide two options: —help and —version. From the GNU manual:
- —version
- This option should direct the program to print information about its name, version, origin, and legal status, all on standard output, and then exit successfully. Other options and arguments should be ignored once this is seen, and the program should not perform its normal function.
- —help
- This option should output brief documentation for how to invoke the program, on standard output, then exit successfully. Other options and arguments should be ignored once this is seen, and the program should not perform its normal function.Near the end of the —help option's output there should be a line that says where to mail bug reports. It should have this format:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Potential Problems
- InhaltsvorschauHere are some useful things to watch out for when writing shell scripts. Being aware of them will not only save you time in tracking down bugs but will also make your scripts more robust, more readable, and above all, more maintainable.
- Don't create massive scripts or functions that try to do everything. Split functionality up into smaller units and place them in functions. This not only makes the code easier to read but makes it easier to debug.
- Always place the shell execution directive (e.g., #!/bin/bash) at the top of your scripts to ensure they will be run by bash.
- Don't use reserved words for variable names. This can become very confusing:
let let="echo" let echo="hello" echo "$echo world"
- Be careful with whitespace. Attempting the following assignment will not give the expected result:
cat = 5
- Don't use the same names for variables and functions:
function letter { echo $1etter } letter=letter letter letterThis causes more confusion that it's worth. While this example is contrived, be on your guard for more subtle examples. To guard against this, try and name your functions using verbs, e.g., function print_letter. - Be careful when using the test operator [...]. The following two if statements are not the same, although they look very similar:
if [ "$var" = 42 ] if [ "$var" -eq 42 ]The first is a string comparison, the second an integer comparison. We suggest using ((...)) for arithmetic comparisons in if statements.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Don't Use bash
- InhaltsvorschauSometimes you might start writing a script and after several hours of work find that you've created a monster with many hundreds of lines of complicated code. This is not always a bad thing, but it is a good idea to always be thinking about whether the job could be done in a better way.Usually the choice of programming language should take place at the design stage. If you are starting from scratch on a Unix system you will have many options, including C and C++, perl, python, and a host of others. They all have their advantages and disadvantages, and no one language will be the best solution for every problem.If you find that your script has a huge amount of processing to do quickly or if the script requires mathematical capabilities beyond simple integer arithmetic, it might be worthwhile considering C or C++ for the job. If you are looking for better portability across systems, python or perl might be a better match to the task.However, even if bash is not suitable in the final solution to a problem, you might find it makes an excellent language for mocking up your solution and trying out various options.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Chapter 12: bash for Your System
- InhaltsvorschauThe first 10 chapters of this book looked at nearly all aspects of bash, from navigating the filesystem and editing the command-line to writing shell scripts and functions using lesser-known features of the shell. This is all very well and good, but what if you have an old version of bash and want the new features shown in this book (or worse yet, you don't have bash at all)?In this chapter we'll show you how to get the latest version of bash and install it on your system, and we'll discuss potential problems you might encounter along the way. We'll also look briefly at the examples that come with bash and how you can report bugs to the bash maintainer.If you have a direct connection to the Internet, you should have no trouble obtaining bash; otherwise, you'll have to do a little more work.The bash home page is located at http://www.gnu.org/software/bash/bash.html and you can find the very latest details of the current distribution and where to obtain it from there.You can also get bash on CD-ROM by ordering it directly from the Free Software Foundation, either via the web ordering page at http://order.fsf.org or from:
The Free Software Foundation (FSF) 59 Temple Place - Suite 330 Boston, MA 02111-1307 USA Phone: +1-617-542-5942 Fax: +1-617-542-2652 Email: order@fsf.org
Having obtained the archive file by one of the above methods, you need to unpack it and install it on your system. Unpacking can be done anywhere—we'll assume you're unpacking it in your home directory. Installing it on the system requires you to have root privileges. If you aren't a system administrator with root access, you can still compile and use bash; you just can't install it as a system-wide utility. The first thing to do is uncompress the archive file by typing gunzip bash-3.0.tar.gz. Then you need to "untar" the archive by typing tar -xf bash-3.0.tar. The -xf means "extract the archived material from the specified file." This will create a directory calledEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Obtaining bash
- InhaltsvorschauIf you have a direct connection to the Internet, you should have no trouble obtaining bash; otherwise, you'll have to do a little more work.The bash home page is located at http://www.gnu.org/software/bash/bash.html and you can find the very latest details of the current distribution and where to obtain it from there.You can also get bash on CD-ROM by ordering it directly from the Free Software Foundation, either via the web ordering page at http://order.fsf.org or from:
The Free Software Foundation (FSF) 59 Temple Place - Suite 330 Boston, MA 02111-1307 USA Phone: +1-617-542-5942 Fax: +1-617-542-2652 Email: order@fsf.org
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Unpacking the Archive
- InhaltsvorschauHaving obtained the archive file by one of the above methods, you need to unpack it and install it on your system. Unpacking can be done anywhere—we'll assume you're unpacking it in your home directory. Installing it on the system requires you to have root privileges. If you aren't a system administrator with root access, you can still compile and use bash; you just can't install it as a system-wide utility. The first thing to do is uncompress the archive file by typing gunzip bash-3.0.tar.gz. Then you need to "untar" the archive by typing tar -xf bash-3.0.tar. The -xf means "extract the archived material from the specified file." This will create a directory called bash-3.0 in your home directory.The archive contains all of the source code needed to compile bash and a large amount of documentation and examples. We'll look at these things and how you go about making a bash executable in the rest of this chapter.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- What's in the Archive
- InhaltsvorschauThe bash archive contains a main directory (bash-3.0 for the current version) and a set of files and subdirectories. Among the first files you should examine are:
- MANIFEST
- A list of all the files and directories in the archive
- COPYING
- The GNU Copyleft for bash
- NEWS
- A list of bug fixes and new features since the last version
- README
- A short introduction and instructions for compiling bash
You should also be aware of two directories:- doc
- Information related to bash in various formats
- examples
- Examples of startup files, scripts, and functions
The other files and directories in the archive are mostly things that are needed during the build. Unless you are going to go hacking into the internal workings of the shell, they shouldn't concern you.The doc directory contains a few articles that are worth reading. Indeed, it would be well worth printing out the manual entry for bash so you can use it in conjunction with this book. The README file gives a short summary of the files.The document you'll most often use is the manual page entry (bash.1). The file is in troff format—that used by the manual pages. You can read it by processing it with the text-formatter nroff and piping the output to a pager utility: nroff -man bash.1 | more should do the trick. You can also print it off by piping it to the lineprinter (lp). This summarizes all of the facilities your version of bash has and is the most up-to-date reference you can get. This document is also available through the man facility once you've installed the package, but sometimes it's nice to have a hard copy so you can write notes all over it.Of the other documents, FAQ is a Frequently Asked Questions document with answers, readline.3 is the manual entry for the readline facility, and article.ms is an article about the shell that appeared in Linux Journal, by the current bash maintainer, Chet Ramey.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Who Do I Turn to?
- InhaltsvorschauNo matter how good something is or how much documentation comes with it, you'll eventually come across something that you don't understand or that doesn't work. In such cases it can't be stressed enough to carefully read the documentation (in computer parlance: RTFM). In many cases this will answer your question or point out what you're doing wrong.Sometimes you'll find this only adds to your confusion or confirms that there is something wrong with the software. The next thing to do is to talk to a local bash guru to sort out the problem. If that fails, or there is no guru, you'll have to turn to other means (currently only via the Internet).If you have any questions about bash, there are currently two ways to go about getting them answered. You can email questions to bash-maintainers@gnu.org or you can post your question to the USENET newsgroups gnu.bash.bug or comp.unix.shell.In both cases either the bash maintainer or some knowledgeable person on USENET will give you advice. When asking a question, try to give a meaningful summary of your question in the subject line.Bug reports should be sent to bug-bash@gnu.org, and include the version of bash and the operating system it is running on, the compiler used to compile bash, a description of the problem, a description of how the problem was produced, and, if possible, a fix for the problem. The best way to do this is with the bashbug script, installed with bash.Before you run bashbug, make sure you've set your EDITOR environment variable to your favorite editor and have exported it (bashbug defaults to emacs, which may not be installed on your system). When you execute bashbug it will enter the editor with a partially blank report form. Some of the information (bash version, operating system version, etc.) will have been filled in automatically. We'll take a brief look at the form, but most of it is self-explanatory.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Appendix A: Related Shells
- InhaltsvorschauThe fragmentation of the UNIX marketplace has had its advantages and disadvantages. The advantages came mostly in the early days: lack of standardization and proliferation among technically knowledgeable academics and professionals contributed to a healthy "free market" for UNIX software, in which several programs of the same type (e.g., shells, text editors, system administration tools) would often compete for popularity. The best programs would usually become the most widespread, while inferior software tended to fade away.But often there was no single "best" program in a given category, so several would prevail. This led to the current situation, where multiplicity of similar software has led to confusion, lack of compatibility, and—most unfortunate of all—the inability of UNIX to capture as big a share of the market as other operating platforms (MS-DOS, Microsoft Windows, Novell NetWare, etc.).The "shell" category has probably suffered in this way more than any other type of software. As we said in the Preface and in Chapter 1, several shells are currently available; the differences between them are often not all that great.Therefore we felt it necessary to include information on shells similar to bash. This appendix summarizes the differences between bash and the following:
- The standard Bourne shell, as a kind of "baseline"
- The IEEE POSIX 1003.2 shell Standard, to which bash adheres and other shells will adhere in the future
- The Korn shell (ksh), a popular commercial shell provided with many UNIX systems
- pdksh, a widely used public domain Korn shell
- zsh, a popular alternative to bash and the Korn shell
Section A.1: The Bourne Shell
Section A.2: The IEEE 1003.2 POSIX Shell Standard
Section A.3: The Korn Shell
Section A.4: pdksh
Section A.5: zsh
Section A.6: Shell Clones and Unix-like Platforms
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The Bourne Shell
- Inhaltsvorschaubash is almost completely backward-compatible with the Bourne shell. The only significant feature of the latter that bash doesn't support is ^ (caret) as a synonym for the pipe (|) character. This is an archaic feature that the Bourne shell includes for its own backward compatibility with earlier shells. No modern UNIX version has any shell code that uses ^ as a pipe.To describe the differences between the Bourne shell and bash, we'll go through each chapter of this book and enumerate the features discussed in the chapter that the Bourne shell does not support. Although some versions of the Bourne shell exist that include a few bash features, we refer to the standard Bourne shell that has been around for many years.
- Chapter 1
- The cd - form of the cd command; tilde (~) expansion; the jobs command; the help built-in.
- Chapter 2
- All. (That is, the Bourne shell doesn't support any of the readline, history, and editing features discussed in this chapter.)
- Chapter 3
- Aliases; prompt string customization; set options. The Bourne shell supports only the following: -e, -k, -n, -t, -u, -v, -x, and -. It doesn't support option names (-o). The shopt built-in. Environment files aren't supported. The following built-in variables aren't supported:
All variables beginning with BASH_All variables beginning with COMPCDPATHDIRSTACKFCEDITFUNCNAMEGROUPSHISTCMDHISTCONTROLHISTFILEHISTIGNOREHISTSIZEHISTFILESIZEHOSTFILEHOSTNAMEHOSTTYPEIGNOREEOFINPUTRCLANGLC_ALLLC_COLLATELC_MESSAGESLINENOMACHTYPEMAILCHECKOLDPWDOPTARGOPTERROPTINDOSTYPEPIPESTATUSPS3PS4POSIXLY_CORRECTPROMPT_COMMANDPWDRANDOMREPLYSECONDSSHELLOPTSSHLVLTIMEFORMATTMOUTauto_resumehistchars- Chapter 4
- Functions; the type command; the local command; the ${#parameter} operator; pattern-matching variable operators (%, %%, #, ##). Extended pattern matching. Command-substitution syntax is different: use the older
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The IEEE 1003.2 POSIX Shell Standard
- InhaltsvorschauThere have been many attempts to standardize UNIX. Hardware companies' monolithic attempts at market domination, fragile industry coalitions, marketing failures, and other such efforts are the stuff of history—and the stuff of frustration.Only one standardization effort has not been tied to commercial interests: the Portable Operating System Interface, known as POSIX. This effort started in 1981 with the /usr/group (now UniForum) Standards Committee, which produced the /usr/group Standard three years later. The list of contributors grew to include the Institute of Electrical and Electronic Engineers (IEEE) and the International Organization for Standardization (ISO).The first POSIX standard was published in 1988. This one, called IEEE P1003.1, covers low-level issues at the system-call level. IEEE P1003.2, covering the shell, utility programs, and user interface issues, was ratified in September 1992 after a six-year effort. In September 2001, a joint revision of both standards was approved. The new standard, covering all the material in the two earlier separate documents, became known as IEEE Standard 1003.1-2001. The latest version of the standard is 1003.1-2004.The POSIX standards were never meant to be rigid and absolute. The committee members certainly weren't about to put guns to the heads of operating system implementers and force them to adhere. Instead, the standards are designed to be flexible enough to allow for both coexistence of similar available software, so that existing code isn't in danger of obsolescence, and the addition of new features, so that vendors have the incentive to innovate. In other words, they are supposed to be the kind of third-party standards that vendors might actually be interested in following.As a result, most UNIX vendors currently comply with both standards. bash is no exception; it is almost 100% POSIX-compliant.The shell part of the standard describes utilities that must be present on all systems, and others that are optional, depending upon the nature of the system. One such option is the User Portability Utilities option, which defines standards for interactive shell use and interactive utilities like the vi editor. The standard—on the order of 2,000 pages—is available through the IEEE; for information, contact the IEEE:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- The Korn Shell
- InhaltsvorschauOne of the first major alternatives to the "traditional" shells, Bourne and C, was the Korn shell, publicly released in 1986 as part of AT&T's "Experimental Toolchest." The Korn shell was written by David Korn at AT&T. The first version was unsupported, but eventually UNIX System Laboratories (USL) decided to give it support when they released it with their version of UNIX (System V Release 4) in 1989. The November 1988 Korn shell is the most widely used version of this shell.The 1988 release is not fully POSIX-compliant—less so than bash. The latest release (1993) has brought the Korn shell into better compliance as well as providing more features and streamlining existing features.The 1993 Korn shell and bash share many features, but there are some important differences in the Korn shell:
- Functions are more like separate entities than part of the invoking shell (traps and options are not shared with the invoking shell).
- Associative arrays are supported.
- Floating-point numbers and expressions are supported.
- Coroutines are supported. Two processes can communicate with one another by using the print and read commands.
- The command print replaces echo. print can have a file descriptor specified and can be used to communicate with coroutines.
- Function autoloading is supported. Functions are read into memory only when they are called.
- One-dimensional arrays are supported, although they are limited in size (4,096 elements in early versions of ksh93, 64K elements in later releases).
- The history list is kept in a file rather than in memory. This allows concurrent instantiations of the shell to access the same history list, a possible advantage in certain circumstances.
- There is no default startup file. If the environment variable ENV is not defined, nothing is read.
- The type command is replaced with the more restrictive whence.
- The primary prompt string (PS1) doesn't allow escaped commands.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - pdksh
- Inhaltsvorschaupdksh (Public Domain Korn shell) is a version of the Korn shell that is a free alternative to bash. pdksh is available as source code in various places on the Internet, including the USENET newsgroup comp.sources.unix, and the pdksh home page http://www.cs.mun.ca/~michael/pdksh/ of the current maintainer, Michael Rendell.pdksh was originally written by Eric Gisin, who based it on Charles Forsyth's public domain Version 7 Bourne shell. It has all Bourne shell features plus some of the POSIX extensions and a few features of its own.pdksh's additional features include user-definable tilde notation, in which you can set up ~ as an abbreviation for anything, not just usernames.Otherwise, pdksh lacks a few features of the official Korn version and bash. In particular, it lacks the following bash features:
- The built-in variable PS4
- The advanced I/O redirectors >| and <>
- The options errexit, noclobber, and privileged
One important advantage that pdksh has over bash is that the executable is only about a third the size and it runs considerably faster. Weighed against this is that it is less POSIX-compliant, has had numerous people add code to it (so it hasn't been as strongly controlled as bash), and isn't as polished a product as bash (for example, the documentation isn't anywhere near as detailed or complete).However, pdksh is a worthwhile alternative for those who want something other than bash and can't obtain the Korn shell.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - zsh
- Inhaltsvorschauzsh is a powerful interactive shell and scripting language with many features found in bash, ksh, and tcsh, as well as several unique features.zsh was originally written by Paul Falsted in the early 1990s and is now maintained by various people.It is freely available and should compile and run on just about any modern version of Unix. Ports for other operating systems are also available. The zsh home page is http://www.zsh.org. The current version is 4.2.1.Some of the main differences between bash and zsh are:
- Extended globbing capabilities
- A slightly more advanced textual completion system
- A powerful multi-line command line editor
- Various visual bells and whistles, such as command prompt color and placement
zsh is a good alternative to bash, especially for "power users."Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Shell Clones and Unix-like Platforms
- InhaltsvorschauThe proliferation of shells has not stopped at the boundaries of UNIX-dom. Many programmers who got their initial experience on UNIX systems and subsequently crossed over into the PC world wished for a nice UNIX-like environment. It's not surprising then that several UNIX shell-style interfaces to small-computer operating systems have appeared, Bourne shell emulations among them.In the past several years, not only shell clones have appeared, but entire Unix "environments." Two of them use shells that we've already discussed. Two others provide their own shell reimplementations. Providing lists of major and minor differences is counterproductive. Instead, this section describes each environment in turn (in alphabetical order), along with contact and Internet download information.Cygnus Consulting (now part of Red Hat) created the cygwin environment. First creating cgywin.dll, a shared library that provides Unix system call emulation, they ported a large number of GNU utilities to various versions of Microsoft Windows. The greatest functionality comes under Windows/NT, Windows 2000, and Windows XP, although the environment can and does work under Windows 95/98/ME, as well.The cygwin environment uses bash for its shell, GCC for its C compiler, and the rest of the GNU utilities for its Unix toolset. A sophisticated mount command provides a mapping of the Windows C:\path notation to Unix filenames.The cygwin project can be found at http://www.cygwin.com.The DJGPP suite provides 32-bit GNU tools for the MS-DOS environment. To quote the web page:DJGPP is a complete 32-bit C/C++ development system for Intel 80386 (and higher) PCs running MS-DOS. It includes ports of many GNU development utilities. The development tools require a 80386 or newer computer to run, as do the programs they produce. In most cases, the programs it produces can be sold commercially without license or royalties.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Appendix B: Reference Lists
- Inhaltsvorschau
Section B.1: Invocation
Section B.2: Prompt String Customizations
Section B.3: Built-In Commands and Reserved Words
Section B.4: Built-In Shell Variables
Section B.5: Test Operators
Section B.6: set Options
Section B.7: shopt Options
Section B.8: I/O Redirection
Section B.9: emacs Mode Commands
Section B.10: vi Control Mode Commands
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Invocation
- InhaltsvorschauTable B-1 and Table B-2 list the options you can use when invoking current versions of bash and the older 1.x version, respectively. The multicharacter options must appear on the command line before the single-character options. In addition to these, any set option can be used on the command line; see Table B-7. Login shells are usually invoked with the options -i (interactive), -s (read from standard input), and -m (enable job control).
Table B-1: Command-line options OptionMeaning-c stringCommands are read from string, if present. Any arguments after string are interpreted as positional parameters, starting with $0.-DA list of all double-quoted strings preceded by $ is printed on the standard ouput. These are the strings that are subject to language translation when the current locale is not C or POSIX. This also turns on the -n option.-iInteractive shell. Ignores signals TERM, INT, and QUIT. With job control in effect, TTIN, TTOU, and TSTP are also ignored.-lMakes bash act as if invoked as a login shell.-o optionTakes the same arguments as set -o.-O, +O shopt-optionshopt-option is one of the shell options accepted by the shopt builtin. If shopt-option is present, -O sets the value of that option; +O unsets it. If shopt-option is not supplied, the names and values of the shell options accepted by shopt are printed on the standard output. If the invocation option is +O, the output is displayed in a format that may be reused as input.-sReads commands from the standard input. If an argument is given to bash, this flag takes precedence (i.e., the argument won't be treated as a script name and standard input will be read).-rRestricted shell. See Chapter 10.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Prompt String Customizations
- InhaltsvorschauTable B-3 shows a summary of the prompt customizations that are available. The customizations \[ and \] are not available in bash versions prior to 1.14. \a, \e, \H, \T, \@, \v, and \V are not available in versions prior to 2.0. \A, \D, \j, \l, and \r are only available in later versions of bash 2.0 and in bash 3.0.
Table B-3: Prompt string customizations CommandMeaning\aThe ASCII bell character (007)\AThe current time in 24-hour HH:MM format\dThe date in "Weekday Month Day" format\D {format}The format is passed to strftime(3) and the result is inserted into the prompt string; an empty format results in a locale-specific time representation; the braces are required\eThe ASCII escape character (033)\HThe hostname\hThe hostname up to the first "."\jThe number of jobs currently managed by the shell\lThe basename of the shell's terminal device name\nA carriage return and line feed\rA carriage return\sThe name of the shell\TThe current time in 12-hour HH:MM:SS format\tThe current time in HH:MM:SS format\@The current time in 12-hour a.m./p.m. format\uThe username of the current user\vThe version of bash (e.g., 2.00)\VThe release of bash; the version and patchlevel (e.g., 3.00.0)\wThe current working directory\WThe basename of the current working directory\#The command number of the current command\!The history number of the current command\$If the effective UID is 0, print a #, otherwise print a $\nnnCharacter code in octal\\Print a backslash\[Begin a sequence of non-printing characters, such as terminal control sequences\]End a sequence of non-printing charactersEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Built-In Commands and Reserved Words
- InhaltsvorschauTable B-4 shows a summary of all built-in commands and reserved words. The letters in the Type column of the table have the following meanings: R = reserved word, blank = Builtin.
Table B-4: Commands and reserved words CommandChapterTypeSummary!5RLogical NOT of a command exit status.:7Do nothing (just do expansions of any arguments)..4Read file and execute its contents in current shell.alias3Set up shorthand for command or command line.bg8Put job in background.bind2Bind a key sequence to a readline function or macro.break5Exit from surrounding for, select, while, or until loop.builtin5Execute the specified shell built-in.case5RReserved word. Multi-way conditional construct.cd1Change working directory.command7Run a command bypassing shell function lookup.compgenDGenerate possible completion matches.completeDSpecify how completion should be performed.continueSkip to next iteration of for, select, while, or until loop.declare6Declare variables and give them attributes.dirs6Display the list of currently remembered directories.disown8Remove a job from the job table.do5RPart of a for, select, while, or until looping construct.done5RPart of a for, select, while, or until looping construct.echo4Expand and print any arguments.elif5RPart of an if construct.else5RPart of an if construct.enable7Enable and disable built-in shell commands.esac5RPart of a case construct.eval7Run the given arguments through command-line processing.exec9Replace the shell with the given program.exit5Exit from the shell.export3Create environment variables.fc2Fix command (edit history file).fg8Put background job in foreground.fi5RPart of an if construct.for5RLooping construct.function4RDefine a function.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Built-In Shell Variables
- InhaltsvorschauTable B-5 shows a complete list of environment variables available in bash 3.0. The letters in the Type column of the table have the following meanings: A = Array, L = colon separated list, R = read-only, U = unsetting it causes it to lose its special meaning.Note that the variables beginning BASH_, beginning COMP, DIRSTACK, FUNCNAME, GLOBIGNORE, GROUPS, HISTIGNORE, HOSTNAME, HISTTIMEFORMAT, LANG, LC_ALL, LC_COLLATE, LC_MESSAGE, MACHTYPE, PIPESTATUS, SHELLOPTS, and TIMEFORMAT are not available in versions prior to 2.0. BASH_ENV replaces ENV found in earlier versions.
Table B-5: Environment variables VariableChapterTypeDescription*4RThe positional parameters given to the current script or function.@4RThe positional parameters given to the current script or function.#4RThe number of arguments given to the current script or function.-ROptions given to the shell on invocation.?5RExit status of the previous command.RLast argument to the previous command.$8RProcess ID of the shell process.!8RProcess ID of the last background command.04RName of the shell or shell script.BASH3The full pathname used to invoke this instance of bash.BASH_ARGC9AAn array of values which are the number of parameters in each frame of the current bash execution call stack. The number of parameters to the current subroutine (shell function or script executed with . or source) is at the top of the stack.BASH_ARGV9AAll of the parameters in the current bash execution call stack. The final parameter of the last subroutine call is at the top of the stack; the first parameter of the initial call is at the bottom.BASH_COMMAND9The command currently being executed or about to be executed, unless the shell is executing a command as the result of a trap, in which case it is the command executing at the time of the trap.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Test Operators
- InhaltsvorschauTable B-6 lists the operators that are used with test and the [...] and [[...]] constructs. They can be logically combined with -a ("and") and -o ("or") and grouped with escaped parenthesis (\( ... \)). The string comparisons < and > and the [[...]] construct are not available in versions of bash prior to 2.0.
Table B-6: Test operators OperatorTrue if...-a filefile exists-b filefile exists and is a block device file-c filefile exists and is a character device file-d filefile exists and is a directory-e filefile exists; same as -a-f filefile exists and is a regular file-g filefile exists and has its setgid bit set-G filefile exists and is owned by the effective group ID-h filefile exists and is a symbolic link-k filefile exists and has its sticky bit set-L filefile exists and is a symbolic link-n stringstring is non-null-N filefile was modified since it was last read-O filefile exists and is owned by the effective user ID-p filefile exists and is a pipe or named pipe (FIFO file)-r filefile exists and is readable-s filefile exists and is not empty-S filefile exists and is a socket-t NFile descriptor N points to a terminal-u filefile exists and has its setuid bit set-w filefile exists and is writeable-x filefile exists and is executable, or file is a directory that can be searched-z stringEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - set Options
- InhaltsvorschauTable B-7 lists the options that can be turned on with the set - arg command. All are initially off except where noted. Full Names, where listed, are arguments to set that can be used with set -o. The Full Names braceexpand, histexpand, history, keyword, and onecmd are not available in versions of bash prior to 2.0. Also, in those versions, hashing is switched with -d.
Table B-7: Options to set OptionFull nameMeaning-aallexportExport all subsequently defined or modified variables.-BbraceexpandThe shell performs brace expansion. This is on by default.-bnotifyReport the status of terminating background jobs immediately.-CnoclobberDon't allow redirection to overwrite existing files.-EerrtraceAny trap on ERR is inherited by shell functions, command substitutions, and commands executed in a subshell environment.-eerrexitExit the shell when a simple command exits with non-zero status. A simple command is a command not part of a while, until, or if; or part of a && or || list; or a command whose return value is inverted by !.emacsUse emacs-style command-line editing.-fnoglobDisable pathname expansion.-HhistexpandEnable ! style history substitution. On by default in an interactive shell.historyEnable command history. On by default in interactive shells.-hhashallDisable the hashing of commands.ignoreeofDisallow CTRL-D to exit the shell.-kkeywordPlace keyword arguments in the environment for a command.-mmonitorEnable job control (on by default in interactive shells).-nnoexecRead commands and check syntax but do not execute them. Ignored for interactive shells.-PphysicalDo not follow symbolic links on commands that change the current directory. Use the physical directory.-pprivilegedScript is running in suid mode.pipefailThe return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - shopt Options
- InhaltsvorschauThe shopt options are set with shopt -s arg and unset with shopt -u arg. See Table B-8 for options to shopt. Versions of bash prior to 2.0 had environment variables to perform some of these settings. Setting them equated to shopt -s.The variables (and corresponding shopt options) were: allow_null_glob_expansion (nullglob), cdable_vars (cdable_vars), command_oriented_history (cmdhist), glob_dot_filenames (dotglob), no_exit_on_failed_exec (execfail). These variables no longer exist.The options extdebug, failglob, force_fignore, and gnu_errfmt are not available in versions of bash prior to 3.0.
Table B-8: Options to shopt OptionMeaning if setcdable_varsAn argument to cd that is not a directory is assumed to be the name of a variable whose value is the directory to change to.cdspellMinor errors in the spelling of a directory supplied to the cd command will be corrected if there is a suitable match. This correction includes missing letters, incorrect letters, and letter transposition. It works for interactive shells only.checkhashCommands found in the hash table are checked for existence before being executed and non-existence forces a PATH search.checkwinsizeChecks the window size after each command and, if it has changed, updates the variables LINES and COLUMNS accordingly.cmdhistAttempt to save all lines of a multiline command in a single history entry.dotglobFilenames beginning with a . are included in pathname expansion.execfailA non-interactive shell will not exit if it cannot execute the argument to an exec. Interactive shells do not exit if exec fails.expand_aliasesAliases are expanded.extdebugBehavior intended for use by debuggers is enabled. This includes: the -F option of declare displays the source filename and line number corresponding to each function name supplied as an argument; if the command run by theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - I/O Redirection
- InhaltsvorschauTable B-9 shows a complete list of I/O redirectors. (This table is also included earlier as Table 7-1.) Note that there are two formats for specifying standard output and error redirection: &>file and >&file. The second of these, and the one used throughout this book, is the preferred way.
Table B-9: I/O redirectors RedirectorFunctioncmd1 | cmd2Pipe; take standard output of cmd1 as standard input to cmd2> fileDirect standard output to file< fileTake standard input from file>> fileDirect standard output to file; append to file if it already exists>| fileForce standard output to file even if noclobber is setn>| fileForce output to file from file descriptor n even if noclobber set<> fileUse file as both standard input and standard outputn<> fileUse file as both input and output for file descriptor n<< labelHere-documentn > fileDirect file descriptor n to filen < fileTake file descriptor n from file>> fileDirect file descriptor n to file; append to file if it already existsn>&Duplicate standard output to file descriptor nn<&Duplicate standard input from file descriptor nn>&mFile descriptor n is made to be a copy of the output file descriptorn<&mFile descriptor n is made to be a copy of the input file descriptor&> fileDirects standard output and standard error to file<&-Close the standard input>&-Close the standard outputn>&-Close the output from file descriptor nn<&-Close the input from file descriptorEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - emacs Mode Commands
- InhaltsvorschauTable B-10 shows a complete list of emacs editing mode commands.
Table B-10: emacs mode commands CommandMeaningCTRL-AMove to beginning of lineCTRL-BMove backward one characterCTRL-DDelete one character forwardCTRL-EMove to end of lineCTRL-FMove forward one characterCTRL-GAbort the current editing command and ring the terminal bellCTRL-JSame as RETURNCTRL-KDelete (kill) forward to end of lineCTRL-LClear screen and redisplay the lineCTRL-MSame as RETURNCTRL-NNext line in command historyCTRL-OSame as RETURN, then display next line in history fileCTRL-PPrevious line in command historyCTRL-RSearch backwardCTRL-SSearch forwardCTRL-TTranspose two charactersCTRL-UKill backward from point to the beginning of lineCTRL-VMake the next character typed verbatimCTRL-V TABInsert a TABCTRL-WKill the word behind the cursor, using whitespace as the boundaryCTRL-X /List the possible filename completions of the current wordCTRL-X ~List the possible username completions of the current wordCTRL-X $List the possible shell variable completions of the current wordCTRL-X @List the possible hostname completions of the current wordCTRL-X !List the possible command name completions of the current wordCTRL-X (Begin saving characters into the current keyboard macroCTRL-X )Stop saving characters into the current keyboard macroCTRL-X eRe-execute the last keyboard macro definedCTRL-X CTRL-RRead in the contents of the readline initialization fileCTRL-X CTRL-VDisplay version information on this instance of bashCTRL-YRetrieve (yank) last item killedDELDelete one character backwardCTRL-[Same as ESC (most keyboards)ESC-BMove one word backwardESC-CChange word after point to all capital lettersESC-DDelete one word forwardESC-FMove one word forwardESC-LChange word after point to all lowercase lettersESC-NNon-incremental forward searchEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - vi Control Mode Commands
- InhaltsvorschauTable B-11 shows a complete list of all vi control mode commands.
Table B-11: vi control mode commands CommandMeaninghMove left one characterlMove right one characterwMove right one wordbMove left one wordWMove to beginning of next non-blank wordBMove to beginning of preceding non-blank wordeMove to end of current wordEMove to end of current non-blank word0Move to beginning of line.Repeat the last a insertion.^Move to first non-blank character in line$Move to end of lineiInsert text before current characteraInsert text after current characterIInsert text at beginning of lineAInsert text at end of lineROverwrite existing textdhDelete one character backwarddlDelete one character forwarddbDelete one word backwarddwDelete one word forwarddBDelete one non-blank word backwarddWDelete one non-blank word forwardd$Delete to end of lined0Delete to beginning of lineDEquivalent to d$ (delete to end of line)ddEquivalent to 0d$ (delete entire line)CEquivalent to c$ (delete to end of line, enter input mode)ccEquivalent to 0c$ (delete entire line, enter input mode)xEquivalent to dl (delete character forwards)XEquivalent to dh (delete character backwards)k or -Move backward one linej or +Move forward one lineGMove to line given by repeat count/ stringSearch forward for string? stringSearch backward for stringnRepeat search forwardNRepeat search backwardf xMove right to next occurrence of xF xMove left to previous occurrence of xt xMove right to next occurrence of x, then back one spaceT xMove left to previous occurrence of x, then forward one space;Redo last character finding command,Redo last character finding command in opposite direction\Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix C: Loadable Built-Ins
- Inhaltsvorschaubash 2.0 introduced a new feature that increased the flexibility of the shell: dynamically loadable built-ins. On systems that support dynamic loading, you can write your own built-ins in C, compile them into shared objects, and load them at any time from within the shell with the enable built-in (see Chapter 7 for details on all of the enable options).This appendix will discuss briefly how to go about writing a built-in and loading it in bash. The discussion assumes that you have experience with writing, compiling, and linking C programs.The bash archive contains a number of pre-written built-ins in the directory examples/loadables/. You can build them by uncommenting the lines in the file Makefile that are relevant to your system, and typing make. We'll take one of these built-ins, tty, and use it as a "case study" for built-ins in general.tty will mimic the standard UNIX command tty. It will print the name of the terminal that is connected to standard input. The built-in will, like the command, return true if the device is a TTY and false if it isn't. In addition, it will take an option, -s, which specifies that it should work silently, i.e., print nothing and just return a result.The C code for a built-in can be divided into three distinct sections: the code that implements the functionality of the built-in, a help text message definition, and a structure describing the built-in so that bash can access it.The description structure is quite straightforward and takes the form:
struct builtin structname = { "builtin_name", function_name, BUILTIN_ENABLED, help_array, "usage", 0 };
builtin_name is the name of the built-in as it appears in bash. The next field, function-name, is the name of the C function that implements the built-in. We'll look at this in a moment. BUILTIN_ENABLED is the initial state of the built-in, whether it is enabled or not. This field should always be set to BUILTIN_ENABLED. help_array is an array of strings which are printed whenEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix D: Programmable Completion
- InhaltsvorschauProgrammable completion is a feature that was introduced in bash 2.0. It extends the built-in textual completion that is discussed in Chapter 2 by providing hooks into the completion mechanism. This means that it is possible to write virtually any form of completion desired. For instance, if you were typing the man command, wouldn't it be nice to be able to hit TAB and have the manual sections listed for you. Programmable completion allows you to do this and much more.This Appendix will only look at the basics of programmable completion. While completion is a feature you are very likely to use in everyday shell operation, you are unlikely to need to delve into the inner depths and actually write your own completion code. Fortunately the feature has been around for some time and there are already several libraries of completion commands developed by other people. We'll just outline the basic commands and procedures needed to use the completion mechanism should you ever need to work on it yourself.In order to be able to do textual completion in a particular way you first have to tell the shell how to do it when you press the TAB key. This is done via the complete command.The main argument of complete is a name that can be the name of a command or anything else that you want textual completion to work with. As an example we will look at the gunzip command that allows compressed archives of various types to be uncompressed. Normally, if you were to type:
$ gunzip [TAB][TAB]you would get a list of filenames from which to complete. This list will include all kinds of things that are unsuitable for the gunzip command. What we really would like is the subset of those files that are suitable for the command to work on. We can set this up by using complete:complete -A file -X '!*.@(Z|gz|tgz)' gunzip
Here we are telling completion mechanism that when the gunzip command is typed in we want it to do something special. The -A flag is an action and takes a variety of arguments. In this case we provideEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Zurück zu Learning the bash Shell
