[ prev | next | top ]

11. Command Line Editing

zsh’s command line editor, ZLE, is quite powerful. It is designed to emulate either emacs or vi; the default is emacs. To set the bindings for vi mode, type bindkey -v. If your EDITOR or VISUAL environment variable is vi, zsh will use vi emulation by default. You can then switch to emacs mode with bindkey -e.

In addition to basic editing, the shell allows you to recall previous lines in the history. In emacs mode, this is done with ˆP (control-P) or (on many terminals) with the cursor-up key:

% ls ˜
-           README      file        mail        pub         tmp
Mailboxes   bin         func        nicecolors  scr         zsh
News        etc         iris        notes       src
% echo foobar
foobar
% ˆP
% echo foobarˆP
% ls ˜_

Pressing ˆP once brings up the previous line (echo foobar); pressing it again brings up the line before that (ls ˜). The cursor is left at the end of the line, allowing you to edit the line if desired before executing it. In many cases, ZLE eliminates the need for the fc command, since it is powerful enough to handle even multiline commands:

% for i in a b c d e
> do
> echo $i
> done
a
b
c
d
e
% ˆP
% for i in a b c d e
 do
 echo $i
 done_

Now you can just move up to the part you want to change...

% for i in _ b c d e
 do
 echo $i
 done

change it, and execute the new command.

% for i in f g h i j
 do
 echo $i
 done
f
g
h
i
j

Also, you can search the history for a certain command using ESC-P, this will look for the last command that started with the (part of the) word at the beginning of the current line. Hitting ESC-P another time gets you the command before that, etc.

% set ESC-P
% setopt autolist
ESC-P

% setopt nocorrect_

Another way is to do an incremental search, emacs-style:

% ˆR

% _
i-search:

% l_ /usr/bin
i-search: l

% date > foofile_c
i-search: le

Suppose you have retrieved an old history event in one of these ways and would like to execute several consecutive old commands starting with this one. ˆO will execute the current command and then put the next command from the history into the editor buffer. Typing ˆO several times will therefore reexecute several consecutive commands from the history. Of course, you can edit some of those commands in between.

In addition to completion (see below), TAB performs expansion if possible.

% ls *.cTAB

% ls foofile.c fortune.c rnd.c strfile.c unstr.c_

For example, suppose you have a bunch of weird files in an important directory:

% ls
  * * *       ; & % $??foo  dspfok        foo.c
  !"foo"!       ‘ \ ‘         foo           rrr

You want to remove them, but you don’t want to damage foo.c. Here is one way to do this:

% rm *TAB

% rm \ \ \*\ \*\ \*\ \ \  \!\"foo\"\! \;\ \&\ %\ \$’´
’foo \‘\ \\\ \‘ dspfok foo foo.c rrr_

When you expand *, zsh inserts the names of all the files into the editing buffer, with proper shell quoting. Now, just move back and remove foo.c from the buffer:

% rm \ \ \*\ \*\ \*\ \ \  \!\"foo\"\! \;\ \&\ %\ \$’´
’foo \‘\ \\\ \‘ dspfok foo _rr

and press return. Everything except foo.c will be deleted from the directory. If you do not want to actually expand the current word, but would like to see what the matches are, type ˆXg.

% rm f*ˆXg

foo    foo.c
% rm f*_

Here’s another trick; let’s say you have typed this command in:

% gcc -o x.out foob.c -g -Wpointer-arith -Wtrigraphs_

and you forget which library you want. You need to escape out for a minute and check by typing ls /usr/lib, or some other such command; but you don’t want to retype the whole command again, and you can’t press return now because the current command is incomplete. In zsh, you can put the line on the buffer stack, using ESC-Q, and type some other commands. The next time a prompt is printed, the gcc line will be popped off the stack and put in the editing buffer automatically; you can then enter the proper library name and press return (or, ESC-Q again and look for some other libraries whose names you forgot).

A similar situation: what if you forget the option to gcc that finds bugs using AI techniques? You could either use ESC-Q again, and type man gcc, or you could press ESC-H, which essentially does the same thing; it puts the current line on the buffer stack, and executes the command run-help gcc, where run-help is an alias for man.

Another interesting command is ESC-A. This executes the current line, but retains it in the buffer, so that it appears again when the next prompt is printed. Also, the cursor stays in the same place. This is useful for executing a series of similar commands:

% cc grok.c -g -lc -lgl -lsun -lmalloc -Bstatic -o b.out
% cc fubar.c -g -lc -lgl -lsun -lmalloc -Bstatic -o b.out
% cc fooble.c -g -lc -lgl -lsun -lmalloc -Bstatic -o b.out

The ESC-’ command is useful for managing the shell’s quoting conventions. Let’s say you want to print this string:

don’t do that; type ’rm -rf \*’, with a \ before the *.

All that is necessary is to type it into the editing buffer:

% don’t do that; type ’rm -rf \*’, with a \ before the *.

press ESC-’ (escape-quote):

% ’don’\’’t do that; type ’\’’rm -rf \*’\’’, with a \ before the *.’

then move to the beginning and add the echo command.

% echo ’don’\’’t do that; type ’\’’rm -rf \*’\’’, with a \ before the *.’
don’t do that; type ’rm -rf \*’, with a \ before the *.

Let’s say you want to create an alias to do this echo command. This can be done by recalling the line with ˆP and pressing ESC-’ again:

% ’echo ’\’’don’\’’\’\’’’\’’t do that; type ’\’’\’\’’’\’’rm -rf
\*’\’’\’\’’’\’’, with a \ before the *.’\’’’

and then move to the beginning and add the command to create an alias.

% alias zoof=’echo ’\’’don’\’’\’\’’’\’’t do that; type ’\’’\’\’’’\’’rm
-rf \*’\’’\’\’’’\’’, with a \ before the *.’\’’’
% zoof
don’t do that; type ’rm -rf \*’, with a \ before the *.

If one of these fancy editor commands changes your command line in a way you did not intend, you can undo changes with ˆ_, if you can get it out of your keyboard, or ˆXˆU, otherwise.

Another use of the editor is to edit the value of variables. For example, an easy way to change your path is to use the vared command:

% vared PATH
> /u/pfalstad/scr:/u/pfalstad/bin/sun4:/u/maruchck/scr:/u/subbarao/bin:/u/maruc
hck/bin:/u/subbarao/scripts:/usr/princeton/bin:/usr/ucb:/usr/bin:/bin:/usr/host
s:/usr/princeton/bin/X11:/./usr/lang:/./usr/etc:/./etc

You can now edit the path. When you press return, the contents of the edit buffer will be assigned to PATH.


[ prev | next | top ]