Chapter 2. Command-Line Editing

It’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.[1] 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.

We should mention up front that both emacs- and vi-modes introduce the potential for clashes with control keys set up by the UNIX terminal interface. Recall the control keys shown in Chapter 1 in Table 1-7, and the sample stty command output. The control keys shown there override their functions in the editing modes.

During the rest of this chapter, we’ll warn you when an editing command clashes with the default setting of a terminal-interface control key.

Enabling Command-Line Editing

bash initially starts interactively with emacs-mode as the default (unless you have started bash with the -noediting option;[2] 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 emacs

or:

$ set -o vi

The 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.

The History List

All 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.

emacs Editing Mode

If 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.

Basic Commands

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

Command

Description

CTRL-B

Move backward one character (without deleting)

CTRL-F

Move forward one character

DEL

Delete one character backward

CTRL-D

Delete one character forward

The 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:

$ [f]grep -l Duchess < ~cam/book/alice_in_wonderland

Now the cursor is on the f, and point is at the beginning of the line, just before the f. If you type DEL, nothing will happen because there are no characters to the left of point. However, if you press CTRL-D (the “delete character forward” command) you will delete the first letter:

$ [g]rep -l Duchess < ~cam/book/alice_in_wonderland

Point is still at the beginning of the line. If this were the desired command, you could hit RETURN now and run it; you don’t need to move the cursor back to the end of the line. However, you could type CTRL-F repeatedly to get there:

$ grep -l Duchess < ~cam/book/alice_in_wonderland[]

At this point, typing CTRL-D wouldn’t do anything, but hitting DEL would erase the final d.

Word Commands

The basic commands are really all you need to get around a command line, but a set of more advanced commands lets you do it with fewer keystrokes. These commands operate on words rather than single characters; emacs-mode defines a word as a sequence of one or more alphanumeric characters.

The word commands are shown in Table 2-2. The basic commands are all single characters, whereas these consist of two keystrokes, ESC followed by a letter. You will notice that the command ESC X, where X is any letter, often does for a word what CTRL-X does for a single character. “Kill” is another word for “delete”; it is the standard term used in the readline library documentation for an “undoable” deletion.

Table 2-2. emacs-mode word commands

Command

Description

ESC-B

Move one word backward

ESC-F

Move one word forward

ESC-DEL

Kill one word backward

ESC-CTRL-H

Kill one word backward

ESC-D

Kill one word forward

CTRL-Y

Retrieve (“yank”) last item killed

To return to our example: if we type ESC-B, point will move back a word. Since the underscore (_) is not an alphanumeric character, emacs-mode will stop there:

$ grep -l Duchess < ~cam/book/alice_in_[w]onderland

The cursor is on the w in wonderland, and point is between the _ and the w. Now let’s say we want to change the -l option of this command from Duchess to Cheshire. We need to move back on the command line, so we type ESC-B four more times. This gets us here:

$ grep -l Duchess < ~[c]am/book/alice_in_wonderland

If we type ESC-B again, we end up at the beginning of Duchess:

$ grep -l [D]uchess < ~cam/book/alice_in_wonderland

Why? Remember that a word is defined as a sequence of alphanumeric characters only. Therefore < is not a word; the next word in the backward direction is Duchess. We are now in position to delete Duchess, so we type ESC-D and get:

$ grep -l []< ~cam/book/alice_in_wonderland

Now we can type in the desired argument:

$ grep -l Cheshire[]< ~cam/book/alice_in_wonderland

If you want Duchess back again you can use the CTRL-Y command. The CTRL-Y “yank” command will undelete a word if the word was the last thing deleted. In this case, CTRL-Y would insert Duchess at the point.

Line Commands

There are still more efficient ways of moving around a command line in emacs-mode. A few commands deal with the entire line; they are shown in Table 2-3.

Table 2-3. emacs-mode line commands

Command

Description

CTRL-A

Move to beginning of line

CTRL-E

Move to end of line

CTRL-K

Kill forward to end of line

Using CTRL-A, CTRL-E, and CTRL-K should be straightforward. Remember that CTRL-Y will always undelete the last thing deleted; if you use CTRL-K, that could be quite a few characters.

Moving Around in the History List

Now we know how to get around the command line efficiently and make changes. But that doesn’t address the original issue of recalling previous commands by accessing the history list. emacs-mode has several commands for doing this, summarized in Table 2-4.

Table 2-4. emacs-mode commands for moving through the history list

Command

Description

CTRL-P

Move to previous line

CTRL-N

Move to next line

CTRL-R

Search backward

ESC-<

Move to first line of history list

ESC->

Move to last line of history list

CTRL-P and CTRL-N move you through the command history. If you have cursor motion keys (arrow keys) you can use them instead. The up-arrow is the same as CTRL-P and the down-arrow is the same as CTRL-N. For the rest of this discussion, we’ll stick to using the control keys because they can be used on all keyboards.

CTRL-P is by far the one you will use most often—it’s the “I made a mistake, let me go back and fix it” key. You can use it as many times as you wish to scroll back through the history list. If you want to get back to the last command you entered, you can hold down CTRL-N until bash beeps at you, or just type ESC->. As an example, you hit RETURN to run the command above, but you get an error message telling you that your option letter was incorrect. You want to change it without retyping the whole thing.

First, you would type CTRL-P to recall the bad command. You get it back with point at the end:

$ grep -l Duchess < ~cam/book/alice_in_wonderland[]

After CTRL-A, ESC-F, two CTRL-Fs, and CTRL-D, you have:

$ grep -[]Duchess < ~cam/book/alice_in_wonderland

You decide to try -s instead of -l, so you type s and hit RETURN. You get the same error message, so you give up and look it up in the manual. You find out that the command you want is fgrep—not grep—after all.

You sigh heavily and go back and find the fgrep command you typed in an hour ago. To do this, you type CTRL-R; whatever was on the line will disappear and be replaced by (reverse-i-search)`':. Then type fgrep, and you will see this:

$ (reverse-i-search)`fgrep': fgrep -l Duchess <~cam/book/ 
   alice_in_wonderland[]

The shell dynamically searches back through the command history each time you type a letter, looking for the current substring in the previous commands. In this example, when you typed f the shell would have printed the most recent command in the history with that letter in it. As you typed more letters, the shell narrowed the search until you ended up with the line displayed above. Of course, this may not have been the particular line you wanted. Typing CTRL-R again makes the shell search further back in the history list for a line with “fgrep” in it. If the shell doesn’t find the substring again, it will beep.

If you try the fgrep command by hitting RETURN, two things will happen. First, of course, the command will run. Second, this line will be entered into the history list at the end, and your “current line” will be at the end as well. You will no longer be somewhere else in the command history.

Another handy trick to save typing if you have already done a search is to type CTRL-R twice in a row. This recalls the previous search string you typed in.[3]

CTRL-P, CTRL-N, and CTRL-R are clearly the most important emacs-mode commands that deal with the command history. The others are less useful but are included for compatibility with the full emacs editor.

Textual Completion

One of the most powerful (and typically underused) features of emacs-mode is its textual completion facility, inspired by similar features in the full emacs editor, the C shell, and (originally) the old DEC TOPS-20 operating system.

The premise behind textual completion is simple: you should have to type only as much of a filename, user name, function, etc., to identify it unambiguously. This is an excellent feature; there is an analogous one in vi-mode. We recommend that you take the time to learn it, since it will save you quite a bit of typing.

There are three commands in emacs-mode that relate to textual completion. The most important is TAB.[4] When you type in a word of text followed by TAB, bash will attempt to complete the name. Then one of four things can happen:

  1. If there is nothing whose name begins with the word, the shell will beep and nothing further will happen.

  2. If there is a command name in the search path, a function name, or a filename that the string uniquely matches, the shell will type the rest of it, followed by a space in case you want to type in more command arguments. Command name completion is only attempted when the word is in a command position (e.g., at the start of a line).

  3. If there is a directory that the string uniquely matches, the shell will complete the filename, followed by a slash.

  4. If there is more than one way to complete the name, the shell will complete out to the longest common prefix among the available choices. Commands in the search path and functions take precedence over filenames.

For example, assume you have a directory with the files tweedledee.c and tweedledum.c. You want to compile the first of these by typing cc tweedledee.c. You type cc twee followed by TAB. This is not an unambiguous prefix, since the prefix “twee” is common to both filenames, so the shell only completes out to cc tweedled. You need to type more letters to distinguish between them, so you type e and hit TAB again. Then the shell completes out to "cc tweedledee.c“, leaving the extra space for you to type in other filenames or options.

If you didn’t know what options were available after trying to complete cc twee, you could press TAB again. bash prints out the possible completions for you and presents your input line again:

$ cc tweedled
tweedledee.c  tweedledum.c
$ cc tweedled

A related command is ESC-?, which expands the prefix to all possible choices, listing them to standard output. Be aware that the completion mechanism doesn’t necessarily expand to a filename. If there are functions and commands that satisfy the string you provide, the shell expands those first and ignores any files in the current directory. As we’ll see, you can force completion to a particular type.

It is also possible to complete other environment entities. If the text being completed is preceded by a dollar sign ($), the shell attempts to expand the name to that of a shell variable (see Chapter 3, for a discussion of shell variables). If the text is preceded by a tilde (~), completion to a username is attempted; if preceded by an at sign (@), a hostname is attempted.

For example, suppose there was a username cameron on the system. If you wanted to change to this user’s home directory, you could just use tilde notation and type the first few letters of the name, followed by a TAB:

$ cd ~ca

which would expand to:

$ cd ~cameron/

You can force the shell to complete to specific things. Table 2-5 lists the standard keys for these.

Table 2-5. Completion command

Command

Description

TAB

Attempt to perform general completion of the text

ESC-?

List the possible completions

ESC-/

Attempt filename completion

CTRL-X /

List the possible filename completions

ESC-~

Attempt username completion

CTRL-X ~

List the possible username completions

ESC-$

Attempt variable completion

CTRL-X $

List the possible variable completions

ESC-@

Attempt hostname completion

CTRL-X @

List the possible hostname completions

ESC-!

Attempt command completion

CTRL-X !

List the possible command completions

ESC-TAB

Attempt completion from previous commands in the history list

If you find that you are interested only in completing long filenames, you are probably better off using ESC-/ rather than TAB. This ensures that the result will be a filename and not a function or command name.

Miscellaneous Commands

Several miscellaneous commands complete emacs editing mode; they are shown in Table 2-6.

Table 2-6. emacs-mode miscellaneous commands

Command

Description

CTRL-J

Same as RETURN

CTRL-L

Clears the screen, placing the current line at the top of the screen

CTRL-M

Same as RETURN

CTRL-O

Same as RETURN, then display next line in command history

CTRL-T

Transpose two characters on either side of point and move point forward by one

CTRL-U

Kills the line from the beginning to point

CTRL-V

Quoted insert

CTRL-[

Same as ESC (most keyboards)

ESC-C

Capitalize word after point

ESC-U

Change word after point to all capital letters

ESC-L

Change word after point to all lowercase letters

ESC-.

Insert last word in previous command line after point

ESC-_

Same as ESC-.

BSD-derived systems use CTRL-V and CTRL-W as default settings for the “quote next character” and “word erase” terminal interface functions, respectively.

A few of these miscellaneous commands are worth discussing, even though they may not be among the most useful emacs-mode commands.

CTRL-O is useful for repeating a sequence of commands you have already entered. Just go back to the first command in the sequence and press CTRL-O instead of RETURN. This will execute the command and bring up the next command in the history list. Press CTRL-O again to enter this command and bring up the next one. Repeat this until you see the last command in the sequence; then just hit RETURN.

Of the case-changing commands, ESC-L is useful when you hit the CAPS LOCK key by accident and don’t notice it immediately. Since all-caps words aren’t used too often in the UNIX world, you probably won’t use ESC-U very often.

CTRL-V will cause the next character you type to appear in the command line as is; i.e., if it is an editing command (or an otherwise special character like CTRL-D), it will be stripped of its special meaning.

If it seems like there are too many synonyms for RETURN, bear in mind that CTRL-M is actually the same (ASCII) character as RETURN, and that CTRL-J is actually the same as LINEFEED, which UNIX usually accepts in lieu of RETURN anyway.

ESC-. and ESC-_ are useful if you want to run several commands on a given file. The usual UNIX convention is that a filename is the last argument to a command. Therefore you can save typing by just entering each command followed by SPACE and then typing ESC-. or ESC-_. For example, say you want to examine a file using more, so you type:

$ more myfilewithaverylongname

Then you decide you want to print it, so you type the print command lp. You can avoid typing the very long name by typing lp followed by a space and then ESC-. or ESC-_; bash will insert myfilewithaverylongname for you.

vi Editing Mode

Like 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

Command

Description

DEL

Delete previous character

CTRL-W

Erase previous word (i.e., erase until a blank)

CTRL-V

Quote the next character

ESC

Enter 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.[5] 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.

Simple Control Mode Commands

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 a non-blank word. The other is any sequence of only alphanumeric characters (letters and digits) plus the underscore (_), or any sequence of only non-alphanumeric characters; we’ll just call this a word.[6]

Table 2-8. Basic vi control mode commands

Command

Description

h

Move left one character

l

Move right one character

w

Move right one word

b

Move left one word

W

Move to beginning of next non-blank word

B

Move to beginning of preceding non-blank word

e

Move to end of current word

E

Move to end of current non-blank word

0

Move to beginning of line

^

Move to first non-blank character in line

$

Move to end of line

All of these commands except the last three can be preceded by a number that acts as a repeat count. Whenever you type a number for the repeat count, the number replaces the command prompt for the duration of the repeat command. If your keyboard has cursor motion keys (“arrow” keys), you can use the left and right arrows to move between characters instead of the h and l keys. Repeat counts will work with the cursor keys as well.

The last two will be familiar to users of UNIX utilities (such as grep) that use regular expressions, as well as to vi users.

Time for a few examples. Let’s say you type in this line and, before you hit RETURN, decide you want to change it:

$ fgrep -l Duchess < ~cam/book/alice_in_wonderland[]

As shown, your cursor is beyond the last character of the line. First, type ESC to enter control mode; your cursor will move back one space so that it is on the d. Then if you type h, your cursor will move back to the n. If you type 3h from the n, you will end up at the r.

Now we will see the difference between the two “word” concepts. Go back to the end of the line by typing $. If you type b, the word in question is alice_in_wonderland, and the cursor will end up on the a:

$ fgrep -l Duchess < ~cam/book/[a]lice_in_wonderland

If you type b again, the next word is the slash (it’s a “sequence” of non-alphanumeric characters), so the cursor ends up over it:

$ fgrep -l Duchess < ~cam/book[/]alice_in_wonderland

However, if you typed B instead of b, the non-blank word would be the entire pathname, and the cursor would end up at the beginning of it—over the tilde:

$ fgrep -l Duchess < [~]cam/book/alice_in_wonderland

You would have had to type b four times—or just 4b—to get the same effect, since there are four “words” in the part of the pathname to the left of /alice_in_wonderland: book, slash, cam, and the leading tilde.

At this point, w and W do the opposite: typing w gets you over the c, since the tilde is a “word,” while typing W brings you to the end of the line. But whereas w and W take you to the beginning of the next word, e and E take you to the end of the current word. Thus, if you type w with the cursor on the tilde, you get to:

$ fgrep -l Duchess < ~[c]am/book/alice_in_wonderland

Then typing e gets you to:

$ fgrep -l Duchess < ~ca[m]/book/alice_in_wonderland

And typing an additional w gets you to:

$ fgrep -l Duchess < ~cam[/]book/alice_in_wonderland

On the other hand, E gets you to the end of the current non-blank word—in this case, the end of the line. (If you find these commands non-mnemonic, you’re right. The only way to assimilate them is through lots of practice.)

Entering and Changing Text

Now that you know how to enter control mode and move around on the command line, you need to know how to get back into input mode so you can make changes and type in additional commands. A number of commands take you from control mode into input mode; they are listed in Table 2-9. All of them enter input mode a bit differently.

Table 2-9. Commands for entering vi input mode

Command

Description

i

Text inserted before current character (insert)

a

Text inserted after current character (append)

I

Text inserted at beginning of line

A

Text inserted at end of line

R

Text overwrites existing text

Most likely, you will use either i or a consistently, and you may use R occasionally. I and A are abbreviations for 0i and $a respectively. To illustrate the difference between i, a, and R, say we start out with our example line:

$ fgrep -l Duchess < ~cam/book[/]alice_in_wonderland

If you type i followed by end, you will get:

$ fgrep -l Duchess < ~cam/bookend[/]alice_in_wonderland

That is, the cursor will always appear to be under the / before alice_in_wonderland. But if you type a instead of i, you will notice the cursor move one space to the right. Then if you type miss_, you will get:

$ fgrep -l Duchess < ~cam/book/miss_[a]lice_in_wonderland

That is, the cursor will always be just after the last character you typed, until you type ESC to end your input. Finally, if you go back to the first a in alice_in_wonderland, type R instead, and then type through_the_looking_glass, you will see:

$ fgrep -l Duchess < ~cam/book/through_the_looking_glas[s]

In other words, you will be replacing (hence R) instead of inserting text.

Why capital R instead of lowercase r? The latter is a slightly different command, which replaces only one character and does not enter input mode. With r, the next single character overwrites the character under the cursor. So if we start with the original command line and type r followed by a semicolon, we get:

$ fgrep -l Duchess < ~cam/book[;]alice_in_wonderland

If you precede r with a number N, it will allow you to replace the next N existing characters on the line—but still not enter input mode. Lowercase r is effective for fixing erroneous option letters, I/O redirection characters, punctuation, and so on.

Deletion Commands

Now that you know how to enter commands and move around the line, you need to know how to delete. The basic deletion command in vi-mode is d followed by one other letter. This letter determines what the unit and direction of deletion is, and it corresponds to a motion command, as listed previously in Table 2-8.

Table 2-10 shows some commonly used examples.

Table 2-10. Some vi-mode deletion commands

Command

Description

dh

Delete one character backwards

dl

Delete one character forwards

db

Delete one word backwards

dw

Delete one word forwards

dB

Delete one non-blank word backwards

dW

Delete one non-blank word forwards

d$

Delete to end of line

d0

Delete to beginning of line

These commands have a few variations and abbreviations. If you use a c instead of d, you will enter input mode after it does the deletion. You can supply a numeric repeat count either before or after the d (or c). Table 2-11 lists the available abbreviations.

Table 2-11. Abbreviations for vi-mode delete commands

Command

Description

D

Equivalent to d$ (delete to end of line)

dd

Equivalent to 0d$ (delete entire line)

C

Equivalent to c$ (delete to end of line, enter input mode)

cc

Equivalent to 0c$ (delete entire line, enter input mode)

X

Equivalent to dl (delete character backwards)

x

Equivalent to dh (delete character forwards)

Most people tend to use D to delete to end of line, dd to delete an entire line, and x (as “backspace”) to delete single characters. If you aren’t a hardcore vi user, you may find it difficult to make sure the more esoteric deletion commands are at your fingertips.

Every good editor provides “un-delete” commands as well as delete commands, and vi-mode is no exception. vi-mode maintains a delete buffer that stores all of the modifications to text on the current line only (note that this is different from the full vi editor). The command u undoes previous text modifications. If you type u, it will undo the last change. Typing it again will undo the change before that. When there are no more undo’s, bash will beep. A related command is . (dot), which repeats the last text modification command.

There is also a way to save text in the delete buffer without having to delete it in the first place: just type in a delete command but use y (“yank”) instead of d. This does not modify anything, but it allows you to retrieve the yanked text as many times as you like later on. The commands to retrieve yanked text are p, which inserts the text on the current line to the right of the cursor, and P, which inserts it to the left of the cursor. The y, p, and P commands are powerful but far better suited to “real vi" tasks like making global changes to documents or programs than to shell commands, so we doubt you’ll use them very often.

Moving Around in the History List

The next group of vi control mode commands we cover allows you to move around in and search your command history. This is the all-important functionality that lets you go back and fix an erroneous command without retyping the entire line. These commands are summarized in Table 2-12.

Table 2-12. vi control mode commands for searching the command history

Command

Description

k or -

Move backward one line

j or +

Move forward one line

G

Move to line given by repeat count

/string

Search backward for string

?string

Search forward for string

n

Repeat search in same direction as previous

N

Repeat search in opposite direction of previous

The first two can also be accomplished with the up and down cursor movement keys if your keyboard has them. The first three can be preceded by repeat counts (e.g., 3k or 3- moves back three lines in the command history).

If you aren’t familiar with vi and its cultural history, you may be wondering at the wisdom of choosing such seemingly poor mnemonics as h, j, k, and l for backward character, forward line, backward line, and forward character, respectively. Well, there actually is a rationale for the choices—other than that they are all together on the standard keyboard. Bill Joy originally developed vi to run on Lear-Siegler ADM-3a terminals, which were the first popular models with addressable cursors (meaning that a program could send an ADM-3a command to move the cursor to a specified location on the screen). The ADM-3a’s h, j, k, and l keys had little arrows on them, so Joy decided to use those keys for appropriate commands in vi. Another (partial) rationale for the command choices is that CTRL-H is the traditional backspace key, and CTRL-J denotes linefeed.

Perhaps + and - are better mnemonics than j and k, but the latter have the advantage of being more easily accessible to touch typists. In either case, these are the most basic commands for moving around the history list. To see how they work, let’s use the same examples from the emacs-mode section earlier.

You enter the example command (RETURN works in both input and control modes, as does LINEFEED or CTRL-J):

$ fgrep -l Duchess < ~cam/book/alice_in_wonderland

but you get an error message saying that your option letter was wrong. You want to change it to -s without having to retype the entire command. Assuming you are in control mode (you may have to type ESC to put yourself in control mode), you type k or - to get the command back. Your cursor will be at the beginning of the line:

$ [f]grep -l Duchess < ~cam/book/alice_in_wonderland

Type w to get to the -, then l to get to the l. Now you can replace it by typing rs; press RETURN to run the command.

Now let’s say you get another error message, and you finally decide to look at the manual page for the fgrep command. You remember having done this a while ago today, so rather than typing in the entire man command, you search for the last one you used. To do this, type ESC to enter control mode (if you are already in control mode, this will have no effect), then type / followed by man or ma. To be on the safe side, you can also type ^ma; the ^ means match only lines that begin with ma.[7]

But typing /^ma doesn’t give you what you want: instead, the shell gives you:

$ make myprogram

To search for “man” again, you can type n, which does another backward search using the last search string. Typing / again without an argument and hitting RETURN will accomplish the same thing.

The G command retrieves the command whose number is the same as the numeric prefix argument you supply. G depends on the command numbering scheme described in Chapter 3 Section 3.4.2.3. Without a prefix argument, it goes to command number 1. This may be useful to former C shell users who still want to use command numbers.

Character-Finding Commands

There are some additional motion commands in vi-mode, although they are less useful than the ones we saw earlier in the chapter. These commands allow you to move to the position of a particular character in the line. They are summarized in Table 2-13, in which x denotes any character.

All of these commands can be preceded by a repeat count.

Table 2-13. vi-mode character-finding commands

Command

Description

fx

Move right to next occurrence of x

Fx

Move left to previous occurrence of x

tx

Move right to next occurrence of x, then back one space

Tx

Move left to previous occurrence of x, then forward one space

;

Redo last character-finding command

,

Redo last character-finding command in opposite direction

Starting with the previous example: let’s say you want to change Duchess to Duckess. Make sure that you’re at the end of the line (or, in any case, to the left of the h in Duchess); then, if you type Fh, your cursor will move to the h:

$ fgrep -l Duc[h]ess < ~cam/book/alice_in_wonderland

At this point, you could type r to replace the h with k. But let’s say you wanted to change Duchess to Dutchess. You would need to move one space to the right of the u. Of course, you could just type l. But, given that you’re somewhere to the right of Duchess, the fastest way to move to the c would be to type Tu instead of Fu followed by l.

As an example of how the repeat count can be used with character-finding commands, let’s say you want to change the filename from alice_in_wonderland to alice. In this case, assuming your cursor is still on the D, you need to get to one character beyond the second slash. To do this, you can type 2fa. Your cursor will then be on the a in alice_in_wonderland.

The character-finding commands also have associated delete commands. Read the command definitions in the previous table and mentally substitute “delete” for move. You’ll get what happens when you precede the given character-finding command with a d. The deletion includes the character given as argument. For example, assume that your cursor is under the a in alice_in_wonderland:

$ fgrep -l Duchess < ~cam/book/[a]lice_in_wonderland

If you want to change alice_in_wonderland to natalie_in_wonderland, one possibility is to type dfc. This means “delete right to next occurrence of c,” i.e., delete “alic”. Then you can type i (to enter input mode) and then “natali” to complete the change.

One final command rounds out the vi control mode commands for getting around on the current line: you can use the pipe character (|) to move to a specific column, whose number is given by a numeric prefix argument. Column counts start at 1; count only your input, not the space taken up by the prompt string. The default repeat count is 1, of course, which means that typing | by itself is equivalent to 0 (see Table 2-8).

Textual Completion

Although the character-finding commands and | are not particularly useful, vi-mode provides one additional feature that we think you will use quite often: textual completion. This feature is not part of the real vi editor, and it was undoubtedly inspired by similar features in emacs and, originally, in the TOPS-20 operating system for DEC mainframes.

The rationale behind textual completion is simple: you should have to type only as much of a filename, user name, function, etc. as is necessary. Backslash () is the command that tells bash to do completion in vi-mode. If you type in a word, hit ESC to enter control mode, and then type , one of four things will happen; they are the same as for TAB in emacs-mode:

  1. If there is nothing whose name begins with the word, the shell will beep and nothing further will happen.

  2. If there is a command name in the search path, a function name, or a filename that the string uniquely matches, the shell will type the rest of it, followed by a space in case you want to type in more command arguments. Command name completion is only attempted when the word is in a command position (e.g., at the start of a line).

  3. If there is a directory that the string uniquely matches, the shell will complete the filename, followed by a slash.

  4. If there is more than one way to complete the name, the shell will complete out to the longest common prefix among the available choices. Commands in the search path and functions take precedence over filenames.

A related command is *. It behaves similarly to ESC-, but if there is more than one completion possibility (number four in the previous list), it lists all of them and allows you to type further. Thus, it resembles the * shell wildcard character.

Less useful is the command =, which does the same kind of expansion as *, but in a different way. Instead of expanding the names onto the command line, it prints them, then gives you your shell prompt back and retypes whatever was on your command line before you typed =. For example, if the files in your directory include tweedledee.c and tweedledum.c, and you type tweedl followed by ESC and then =, you will see this:

$ cc tweedl
tweedledee.c tweedledum.c

It is also possible to expand other environment entities, as we saw in emacs-mode. If the text being expanded is preceded by a dollar sign ($), the shell will attempt to expand the name to that of a shell variable. If the text is preceded by a tilde (~), expansion to a username is attempted; if preceded by an at sign (@), a hostname.

Miscellaneous Commands

Several miscellaneous commands round out vi-mode; some of them are quite esoteric. They are listed in Table 2-14.

Table 2-14. Miscellaneous vi-mode commands

Command

Description

~

Invert (twiddle) case of current character(s)

-

Append last word of previous command, enter input mode

CTRL-L

Clear the screen and redraw the current line on it; good for when your screen becomes garbled

#

Prepend # (comment character) to the line and send it to the history list; useful for saving a command to be executed later without having to retype it[8]

[8] The line is also “executed” by the shell. However, # is the shell’s comment character, so the shell ignores it.

The first of these can be preceded by a repeat count. A repeat count of n preceding the ~ changes the case of the next n characters. The cursor will advance accordingly.

A repeat count preceding _ causes the nth word in the previous command to be inserted in the current line; without the count, the last word is used. Omitting the repeat count is useful because a filename is usually the last thing on a UNIX command line, and because users often run several commands in a row on the same file. With this feature, you can type all of the commands (except the first) followed by ESC-_, and the shell will insert the filename.

The fc Command

fc 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 4, fc -l 2 4, etc.

The other important option to fc is -e for “edit.” This is useful as an “escape hatch” from vi- and emacs-modes if you aren’t used to either of those editors. You can specify the pathname of your favorite editor and edit commands from your history list; then when you have made the changes, the shell will actually execute the new lines.

Let’s say your favorite editor is a little home-brew gem called zed. You could edit your commands by typing:

$ fc -e /usr/local/bin/zed

This seems like a lot of work just to fix a typo in your previous command; fortunately, there is a better way. You can set the environment variable FCEDIT to the pathname of the editor you want fc to use. If you put a line in your .bash_profile or environment file saying:[9]

FCEDIT=/usr/local/bin/zed

you will get zed when you invoke fc. If FCEDIT isn’t set, then bash uses whatever the variable EDITOR is set to. If that’s also not set, then bash defaults to vi.

fc is usually used to fix a recent command. When used without options, it handles arguments a bit differently than it does for the fc -l variation discussed earlier:

  • With no arguments, fc loads the editor with the most recent command.

  • With a numeric argument, fc loads the editor with the command with that number.

  • With a string argument, fc loads the most recent command starting with that string.

  • With two arguments to fc, the arguments specify the beginning and end of a range of commands, as above.

Remember that fc actually runs the command(s) after you edit them. Therefore, the last-named choice can be dangerous. bash will attempt to execute all commands in the range you specify when you exit your editor. If you have typed in any multi-line constructs (like those we will cover in Chapter 5), the results could be even more dangerous. Although these might seem like valid ways of generating “instant shell programs,” a far better strategy would be to direct the output of fc -ln with the same arguments to a file; then edit that file and execute the commands when you’re satisfied with them:

$ fc -l cp > lastcommands$ vi lastcommands$ source lastcommands

In this case, the shell will not try to execute the file when you leave the editor!

There is one final option with fc. fc -s allows you to rerun a command. With an argument, fc will rerun the last command starting with the given string. Without an argument, it will rerun the previous command. The -s option also allows you to provide a pattern and replacement. For example, if you typed:

$ cs prog.c

You could correct it with fc -s cs=cc. This can be combined with the string search: fc -s cs=cc cs. The last occurrence of cs will be found and replaced with cc.

History Expansion

If 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

Command

Description

!

Start a history substitution

!!

Refers to the last command

! n

Refers to command line n

!- n

Refers to the current command line minus n

! string

Refers to the most recent command starting with string

!? string?

Refers to the most recent command containing string; the ending ? is optional

^ string1^string2

Repeat the last command, replacing string1 with string2

By 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.list

Instead 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.

Table 2-16. Word designators

Designator

Description

0

The zeroth (first) word in a line

n

The nth word in a line

^

The first argument (the second word)

$

The last argument in a line

%

The word matched by the most recent ?string search

x-y

A range of words from x to y. -y is synonymous with 0-y

*

All words but the zeroth (first); synonymous with 1-$.; if there is only one word on the line, an empty string is returned

x *

Synonymous with x-$

x-

The words from x to the second to last word

The word designator follows the event designator, separated by a colon. You could, for example, repeat the previous command with different arguments by typing !!:0 followed by the new arguments.

Event designators may also be followed by modifiers. The modifiers follow the word designator, if there is one. Table 2-17 lists the available modifiers.

Table 2-17. Modifiers

Modifier

Description

h

Removes a trailing pathname component, leaving the head

r

Removes a trailing suffix of the form .xxx

e

Removes all but the trailing suffix

t

Removes all leading pathname components, leaving the tail

p

Prints the resulting command but doesn’t execute it

q

Quotes the substituted words, escaping further substitutions

x

Quotes the substituted words, breaking them into words at blanks and newlines

s/old/new/

Substitutes new for old

More than one modifier may be used with an event designator; each one is separated by a colon.

History expansion is fine for re-executing a command quickly, but it has been superseded by the command-line editing facilities that we looked at earlier in this chapter. Its inclusion is really only for completeness, and we feel you are better off mastering the techniques offered in the vi or emacs editing modes.

readline

bash’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 readline Startup File

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 "C-t<">: end-of-line. The C- is the escape sequence prefix for Control. The advantage of the key sequence is that you can specify a sequence of keys for an action. In our example, once readline has read this line, typing a CTRL-T will cause the cursor to move to the end of the line.

The end-of-line in the previous example is a readline function. There are over 60 functions that allow you to control everything from cursor motions to changing text and command completion (for a complete list, see the bash manual page). All of the emacs and vi editing mode commands that we looked at in this chapter have associated functions. This allows you to customize the default modes or make up completely new ones using your own key sequences.

Besides the readline functions, you can also bind a macro to a key sequence. A macro is simply a sequence of keystrokes inside single or double quotes. Typing the key sequence causes the keys in the macro to be entered as though you had typed them. For example, we could bind some text to CTRL-T; "C-t<">: <">Curiouser and curiouser!<">. Hitting CTRL-T would cause the phrase Curiouser and curiouser! to appear on the command line.

If you want to use single or double quotes in your macros or key sequence, you can escape them by using a backslash (). Table 2-18 lists the common escape sequences.

Table 2-18. Escape sequences

Sequence

Description

C-

Control key prefix

M-

Meta (Escape) key prefix

e

The escape character

\

The backslash character ()

<">

The double quote character (<">)

'

The single quote character (')

readline also allows simple conditionals in the .inputrc. There are three directives: $if, $else, and $endif. The conditional of the $if can be an editing mode, a terminal type, or an application-specific condition.

To test for an editing mode, you can use the form mode= and test for either vi or emacs. For instance, to set up readline so that setting CTRL-T will take place only in emacs mode, you could put the following in your .inputrc:

$if mode=emacs
"C-t": "Curiouser and curiouser!"
$endif

Likewise, to test for a terminal type, you can use the form term=. You must provide the full terminal name on the right-hand side of the test. This is useful when you need a terminal-specific key binding. You may, for instance, want to bind the function keys of a particular terminal type to key sequences.

If you have other applications that use readline, you might like to keep your bash-specific bindings separate. You can do this with the last of the conditionals. Each application that uses readline sets its own variable, which you can test for. To test for bash specifics, you could put $if bash into your .inputrc.

readline variables

readline has its own set of variables that you can set from within your .inputrc. Table 2-19 lists them.[10]

Table 2-19. readline variables

Variable

Description

bell-style

If set to none, readline never rings the bell (beeps). If set to visible, readline will attempt to use a visible bell. If set to audible, it will attempt to ring the bell. The default is audible.

comment-begin

The string to insert when the readline insert-comment command is executed. The default is a #.

completion-query-items

Determines when the user is asked to see further completions if the number of completions is greater than that given. The default is 100.

convert-meta

If set to On, converts characters with the eighth bit set to an ASCII key sequence by stripping the eighth bit and prepending an escape character. The default is On.

disable-completion

If set to On, inhibits word completion. Completion characters will be inserted into the line as if they had been mapped to self-insert. The default is Off.

editing-mode

Sets the editing mode to vi or emacs.

enable-keypad

If set to On, readline tries to enable the keyboard’s application keypad when it is called. Some systems need this to enable the arrow keys. The default is Off.

expand-tilde

If set to On, tilde expansion is attempted when readline attempts word completion. The default is Off.

horizontal-scroll-mode

Set to On means that lines will scroll horizontally if you type beyond the right-hand side of the screen. The default is Off, which wraps the line onto a new screen line.

input-meta

If set to On, eight-bit input will be accepted. The default is Off. This is synonymous with meta-flag.

keymap

Sets readline’s current keymap for bindings. Acceptable names are emacs, emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, vi-command and vi-insert. The default is emacs. Note that the value of editing-mode also affects the keymap.

mark-directories

If set to On, completed directory names have a slash appended.

mark-modified-lines

If set to On, displays an asterisk at the start of history lines that have been modified. The default is Off.

meta-flag

If set to On, eight-bit input will be accepted. The default is Off.

output-meta

If set to On, displays characters with the eighth bit set directly. The default is Off.

show-all-if-ambiguous

If set to On, words with more than one possible completion are listed instead of ringing the bell. The default is Off.

visible-stats

If set to On, a character denoting a file’s type as reported by the stat system call is appended to the filename when listing possible completions. The default is Off.

To set any of the variables, you can use the set command in your .inputrc. For example, to set vi-mode when you start up, you could place the line set editing-mode vi in your .inputrc. Every time bash starts it would change to vi-mode.

Key Bindings Using bind

If you want to try out key bindings or you want to see what the current settings are, you can do it from the bash command line by using the bind command. The binding syntax is the same as that of the .inputrc file, but you have to surround each binding in quotes so that it is taken as one argument.

To bind a string to CTRL-T, we could type bind `"C-t<">: <">Curiouser and curiouser!"'. This would bind the given string to CTRL-T just as in the .inputrc, except that the binding will apply only to the current shell and will cease once you log out.

bind also allows you to print out the bindings currently in effect by typing bind -P.[11] If you do so, you’ll see things like:

               abort can be found on "C-g", "C-xC-g", "eC-g".
               accept-line can be found on "C-j", "C-m".
               alias-expand-line is not bound to any keys
               arrow-key-prefix is not bound to any keys
               backward-char can be found on "C-b", "eOD", "e[D".
               ...

If you just want to see the names of the readline functions, you can use bind -l.

You can also unbind a function by using bind -u along with the name of the function; all keys for that function will then be unbound. Unbinding a key sequence can be done with bind -r followed by the sequence.

bind -x is useful if you want to bind a shell command to a key sequence. For example, bind -x `"C-l”:ls' binds CTRL-L to the ls command. Hitting CTRL-L would then give a directory listing.

Another option you might find useful is -p. This prints out the bindings to standard output in a format that can be re-read by bind, or used as a .inputrc file. So, to create a complete .inputrc file that you can then edit, you could type bind -p > .inputrc.

To read the file back in again you can use another option, -f. This option takes a filename as its argument and reads the key bindings from that file. You can also use it to update the key bindings if you’ve just modified your .inputrc.

Keyboard Habits

In 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.

  • Delete using DEL (or whatever your “erase” key is) and CTRL-D; as with CTRL-F and CTRL-B, hold down to repeat if necessary. Use CTRL-K to erase the entire line.

  • Use CTRL-P and CTRL-N (or the up and down arrow keys) to move through the command history.

  • Use CTRL-R to search for a command you need to run again.

  • Use TAB for filename completion.

After a few hours spent learning these keystrokes, you will wonder how you ever got along without command-line editing.



[1] You will get the most out of these sections if you are already familiar with the editor(s) in question. Good sources for more complete information on the editors are the O’Reilly books Learning the vi Editor, by Linda Lamb and Arnold Robbins, and Learning GNU Emacs, by Debra Cameron, James Elliott, and Marc Loy.

[2] -nolineediting in versions of bash prior to 2.0.

[3] Not available in versions of bash prior to 2.05a.

[4] emacs users will recognize this as minibuffer completion.

[5] In particular, versions of UNIX derived from 4.x BSD have all of these commands built in.

[6] Neither of these definitions is the same as the definition of a word in emacs-mode.

[7] Fans of vi and search utilities like grep should note that caret (^) for beginning-of-line is the only context operator vi-mode provides for search strings.

[9] See Chapter 3 for information on the bash startup file .bash_profile.

[10] The variables disable-completion, enable-keypad, input-meta, mark-directories, and visible-stats are not available in versions of bash prior to 2.0.

[11] Versions of bash prior to 2.0 use -d instead of -p, and -v instead of -P. Also, the -r, -V, -S, -s, -u, and the new -v and -x options are not available in these older versions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.23.127.197