Introduction to KornShell

Most UNIX variants allow you to select among several shells. Because of its versatility and ease of use, many system administrators configure the KornShell for new users. The KornShell was derived from the Bourne Shell and has much of the same functionality of the Bourne Shell. ksh is the program you run on most UNIX systems, including HP-UX, that supplies KornShell functionality. It is also often referred to as the K shell. I use ksh throughout this chapter. You can use the ksh in the following three ways:

  • Interactively type commands on the command line.

  • Group commonly executed sets of commands into command files that you can execute by typing the name of the file.

  • Create KornShell programs using the structured programming techniques of the shell.

These three techniques are listed in the order in which you'll probably use them. First, you log in and use interactive commands. Then you group together commonly used commands and execute them with a single command. Finally, you may want to create sophisticated shell scripts.

For this reason, I describe these aspects of the KornShell in the order in which they are listed. The command file and programming aspects of the KornShell are covered as part of the Shell Programming Chapter 28.

The examples in this chapter are performed on a variety of different systems, not just HP-UX. This is because many system administrators use ksh on several different UNIX variants. You would probably find both your user setup and the operation of the KornShell on other systems similar to the description in this chapter. Much of the setup of any shell is performed by the system administrator, so you will surely find differences in your KornShell setup compared with what is shown in this chapter. In general, however, the operation of the KornShell is similar from one system to another.

Startup Files

The first activity you perform after you log into the system is to issue commands at the prompt. A command you may want to issue immediately is ls -al. Here is what I see on my system after executing this command, producing a long listing of all files:

martyp $ ls -al
total 22
drwxr-xr-x   2 martyp   staff        512 Mar 15 11:37.
drwxrwxr-x   4 root     sys          512 Mar  4 09:24 ..
-rw-r--r--   1 martyp   staff        124 Mar 15 11:36 .cshrc
-rw-r--r--   1 martyp   staff        562 Mar  4 09:24 .profile
-rw-------  1 martyp   staff      7056 Apr  6 07:24 .sh_history
martyp $

This produces a short list of files. Some of these files, such as .profile and .cshrc, are startup files for ksh and the C shell, respectively. Upon logging in to a system, you normally execute system startup files for your shell and then execute any local startup files that you have in your home directory. In this case, I have a minimal ksh startup file in my home directory - only a .profile that has very little in it. Virtually all the startup activity for this user comes from the system profile, usually /etc/profile. You can usually read /etc/profile, so you can see what your system administrator has set up for you and other users. You can then modify your local .profile to include a variety of functionality. Your local .profile is usually run at login, immediately after the system /etc/profile.

After running all the startup scripts associated with your ksh login, your environment is set up for you. Although our local .profile didn't do much other than set up our prompt, a lot of setup took place with the system files that were run.

Another file you have is called the Environment file. This file name is defined by the environment variable ENV. This file is usually .kshrc in your home directory. Using the environment file, you can define which options, aliases, and other information will be passed to subprocesses. By default, your existing environment variables are passed to subprocesses. You can use the environment file to pass other information along as well.

You should take a look at your ksh startup files, including /etc/profile, .profile, and .kshrc.

We'll discuss much of the specific ksh functionality provided for you as part of your startup programs in the upcoming sections.

The History File, .sh_history

ksh keeps a history list of the commands you have issued. If you wish to reissue a command or view a command you earlier issued, you can use the history list. By default, .sh_history in your home directory is used as a history file. When your system administrator creates your ksh home directory, this file is probably present and used as your default history file.

By default, most systems save the 128 most recently executed commands. You can specify any number of commands to be included in the history list. The following line sets the history list to 200:

HISTSIZE=200

Most users make this entry in their home .profile. After you have added this line to your .profile, the history list is set to 200.

Recalling from the History List

You can view the most recent commands issued, along with their corresponding line numbers, with the history command as shown in the following example:

martyp $ history
116     history 128
117     history 128 | more
118     history 200
119     alias
120     history 1
121     inv
122     env
123     env | more
124     history 1
125     more .profile
126     env | grep HIS
127     exit
128     env
129     env | grep HIS
130     more .profile
131     history
martyp $

Notice in this example that command number 127 is the exit, or command to log out, from the last session. Command number 128 is the env command I issued immediately upon establishing the next session.

We can also print the history list without line numbers using the -n option, as shown in the following example:

martyp $ history -n
        history 128 | more
        history 200
        alias
        history 1
        inv
        env
        env | more
        history 1
        more .profile
        env | grep HIS
        exit
        env
        env | grep HIS
        more .profile
        history
        history -n
martyp $

To produce a complete list of commands in the history list, we issue the following command:

martyp $ history 0
5       env
6       more .profile
7       set
8       env | grep CDP
9       env | grep cdp
10      echo $SHELLL
11      echo $SHELL
12      more .profile
13      ll
14      ls -al /etc/profile
15      more /etc/profile
16      more /etc/profile | grep PS
17      exhoecE
18      ECHO
19      echo $ENV
20      env | more
21      echo $ENV
22      env | more
23      env | grep ENV
24      env | grep env
25      more /usr/bin/env
26      ls -al
27      more /etc/.kshrc
28      find / -name .kshrc
29      more /etc/passwd
30      more /etc/passwd | grep /home
31      ll /home/oracle
32      ls -al /home/oracle
33      ll /home
34      ls -al /home
35      ls -al /home/ptc-nfs
36      ls -al /home/ptc-nfs | more
37      ls -al /root
38      cd /root/users
39      ls -al
40      ls -al verasu
41      ls -al rodtsu
42       cd rodtsu
43      more .kshrc
44      more .env
45      ls
46      ls -l
47      ls -a
48      more .kshrc
49      cd ..
50      ls -al
51      ls -al | more
52      exit
53      ls -al
54      more .sh*
55      history
56      env | grep his
57      env | grep HIS
58      env | grep IS
59      env | more
60       env | grep FC
61      env | grep EDI
62      history
63      echo $HISTIZE
64      echo $HISTSIZE
65      env | more
66      ls -al
67      history 128
68      history
69      history 1 104
70      exit
71      alias
72      more /etc/profile | grep alias
73      ll
74      la -al
75      ls -al
76      more .profile
77      ls -al
78      more .cshrc
79      alias ll="ls -al"
80      aliase
81      alias
82      ll
83      exit
84      alias
85      alias
86      history
87      fc -l
88      man fc
89      man fc
90      man fc
91      alias
92      ps
93      ps -ef
94      ps -efl
95      ps
96      ls -alF
97      ls -al
98      alias ls="ls -al"
99      alias
100     ls
101     alias
102     unalias ls
103     ls
104     ls -al
105     alias
106     history
107     alias
108     unalias history
109     history
110     fc -l
111     history
112     alias hisotry="fc -l"
113     history
114     alias history="fc -l"
115     history
116     history 128
117     history 128 | more
118     history 200
119     alias
120     history 1
121     inv
122     env
123     env | more
124     history 1
125     more .profile
126     env | grep HIS
127     exit
128     env
129     env | grep HIS
130     more .profile
131     history
132     history 0
martyp $

history 0 prints from the very first command, zero, to the present command. Because only 128 commands are saved by default, the first few oldest commands, zero through four, dropped off the history list. This means that we really started at command number five when we requested to start the list from command number zero.

To produce a list from command 100 to the present command, we issue the following:

martyp $ history 100
100     ls
101     alias
102     unalias ls
103     ls
104     ls -al
105     alias
106     history
107     alias
108     unalias history
109     history
110     fc -l
111     history
112     alias hisotry="fc -l"
113     history
114     alias history="fc -l"
115     history
116     history 128
117     history 128 | more
118     history 200
119     alias
120     history 1
121     inv
122     env
123     env | more
124     history 1
125     more .profile
126     env | grep HIS
127     exit
128     env
129     env | grep HIS
130     more .profile
131     history
132     history 0
133     history
134     history -n
135     history 100
martyp $

To list the current command and the 20 commands preceding it, we issue the following:

martyp $ history -20
116     history 128
117     history 128 | more
118     history 200
119     alias
120     history 1
121     inv
122     env
123     env | more
124     history 1
125     more .profile
126     env | grep HIS
127     exit
128     env
129     env | grep HIS
130     more .profile
131     history
132     history 0
133     history
134     history -n
135     history 100
136     history -20
martyp $

The -20 goes back from the current command a full 20 commands. In this case, history is using the current command as the default place to begin producing the list. You can list the last 20 commands preceding the current command by specifying the range -1 -20 as shown in the following example:

martyp $ history -1 -20
136     history -20
135     history 100
134     history -n
133     history
132     history 0
131     history
130     more .profile
129     env | grep HIS
128     env
127     exit
126     env | grep HIS
125     more .profile
124     history 1
123     env | more
122     env
121     inv
120     history 1
119     alias
118     history 200
117     history 128 | more
martyp $

Notice in this example that the current command, history -1 -20, is not shown in the list because the -1 starts the list with the preceding command. This is effectively producing a range of commands to list.

You can also reverse the order of the last 20 commands by specifying --20 first and then the -1 as shown in the following example:

martyp $ history -20 -1
118     history 200
119     alias
120     history 1
121     inv
122     env
123     env | more
124     history 1
125     more .profile
126     env | grep HIS
127     exit
128     env
129     env | grep HIS
130     more .profile
131     history
132     history 0
133     history
134     history -n
135     history 100
136     history -20
137     history -1 -20
martyp $

You can also produce a list from the last time that a command was issued to the current command. The following example shows producing a list from the last fc command to the current command:

martyp $ history fc
110     fc -l
111     history
112     alias hisotry="fc -l"
113     history
114     alias history="fc -l"
115     history
116     history 128
117     history 128 | more
118     history 200
119     alias
120     history 1
121     inv
122     env
123     env | more
124     history 1
125     more .profile
126     env | grep HIS
127     exit
128     env
129     env | grep HIS
130     more .profile
131     history
132     history 0
133     history
134     history -n
135     history 100
136     history -20
137     history -1 -20
138     history -20 -1
139     history
140     history grep
141     history env
142     history
143     history fc
martyp $

You can also reverse this list using the -r option as shown in the following example:

martyp $ history -r fc
144     history -r fc
143     history fc
142     history
141     history env
140     history grep
139     history
138     history -20 -1
137     history -1 -20
136     history -20
135     history 100
134     history -n
133     history
132     history 0
131     history
130     more .profile
129     env | grep HIS
128     env
127     exit
126     env | grep HIS
125     more .profile
124     history 1
123     env | more
122     env
121     inv
120     history 1
119     alias
118     history 200
117     history 128 | more
116     history 128
115     history
114     alias history="fc -l"
113     history
112     alias hisotry="fc -l"
111     history
110     fc -l
martyp $

Having access to this history list is a great feature of the KornShell. You can view all the commands you have issued, including your typing errors, in any format you wish. In the next section, we start using the commands in the history list by recalling them.

Re-executing Commands with r

You can reissue a command with the r command. To reissue the last command, you simply type r. In the following example, I issue the command history 5 to view the last five commands from the history list. I then type r to reissue the last command, and again the last five commands are listed:

martyp $ history -5
301     whoami
302     pwd
303     more /etc/passwd
304      ps -efl
305     cat .profile
306     history -5
martyp $ r
history -5
302     pwd
303     more /etc/passwd
304      ps -efl
305     cat .profile
306     history -5
307     history -5
martyp $

You can reissue a specific command number by typing r, a space, and the number of the command you wish to reissue. In the following example, I issue the history command number 302:

martyp $ history
294     history -5
295     whoami
296     pwd
297     more /etc/passwd
298     ps -efl
299     cat /etc/profile
300     history 5
301     whoami
302     pwd
303     more /etc/passwd
304      ps -efl
305     cat .profile
306     history -5
307     history -5
308     history -5
309     history
martyp $ r 302
pwd
/home/martyp
martyp $

You can also give the name of the command you wish to reissue. Let's say that you want to reissue the last fc command. You would simply give the letter "f" along with the r command, and the last command that started with f would be reissued as shown in the following example:

martyp $ history
308     history -5
309     history
310     pwd
311     whoami
312     pwd
313     cat /etc/profile
314     ls
315     fc -l
316     env
317     who
318     cat /etc/passwd
319     ls -al
320     history
321     more .profile
322     set
323     history
martyp $ r f
fc -l
309     history
310     pwd
311     whoami
312     pwd
313     cat /etc/profile
314     ls
315     fc -l
316     env
317     who
318     cat /etc/passwd
319     ls -al
320     history
321     more .profile
322     set
323     history
324     fc -l
martyp $

You can also perform some substitution with the r command. If you issued the vi command earlier and want to rerun vi but specify a different file name to edit, you can substitute a new file name. The following example shows reissuing an earlier vi command, except now we'll replace the original filename we edited, .profile, with the new filename we want to edit, .kshrc. In this example, we'll first run the history command, then reissue the vi command to edit .kshrc, and then we'll run the command again to see our revised vi command:

martyp $ history
316     env
317     who
318     cat /etc/passwd
319     ls -al
320     history
321     more .profile
322     set
323     history
324     fc -l
325     vi .profile
326     set
327     ls -al
328     env
329     who
330     more /etc/passwd | grep marty
331     history
martyp $ r vi .profile=.kshrc
martyp $ history
318     cat /etc/passwd
319     ls -al
320     history
321     more .profile
322     set
323     history
324     fc -l
325     vi .profile
326     set
327     ls -al
328     env
329     who
330     more /etc/passwd | grep marty
331     history
332     vi .kshrc
333     history
martyp $

This command substitutes .kshrc for .profile on the command line.

This leads us to more advanced command-line editing. You may want to recall a command earlier issued and edit the command line using vi editor commands. The next section covers command-line editing.

Fetching Commands Using vi Directives

You can edit entries in your history list with either the vi or emacs editor. I will cover the vi editor in this chapter, because it is the most widely used on UNIX systems. You can, however, perform all the same functions shown in this chapter with the emacs editor.

You edit the history list using vi the same way you edit a file using vi. You press the escape key and use standard vi keys for moving up and down, left and right, inserting deleting, and changing text. In this section, I cover fetching a command from the history list using vi commands and then I cover editing the command after you have restored it to the command line. After the command has been edited to your liking, you press enter to execute the command and place it at the very bottom of the command list.

Your editor is normally set in either your local .profile or /etc/profile. You can view these files to see what editor has been set for you by your system administrator. When I issue the env and set commands on my system, both report EDITOR=vi. This corresponds with my /etc/profile which has the editor set to vi.

Let's first take a look at fetching some previously issued commands using vi. The examples in this section use vi functionality that is described in both the vi chapter and on the vi quick reference card. The k, j, G, and search commands in this section operate in the same manner on the command line as they would if you were using vi to edit a file.

Pressing the escape key and a command allows you to perform various functions in the ksh. The following example shows producing the history list and issuing escape k to recall the previous command:

martyp $ history
125     man fc
126     set | more
127      exit
128     history
129     k
130     env | more
131     set | more
132     more .profile
133     more .profile | grep rof
134     more .profile | grep vi
135     more /etc/profile | grep vi
136     set |grep edit
137     set | grep vi
138     env | grep vi
139     history
140     who
martyp $ history
						

Issuing escape k recalled the last command issued, in this case the who command at line 140. Each time you press k, the preceding ksh command is fetched. This is the same as pressing escape and the - (hyphen) key. You can specify the number of commands you wish to go back in the history list with escape nk, where n is the number of commands you want to go back in the history list. The following example shows issuing escape 5k to fetch the fifth command back in the history list:


martyp $ history
125     man fc
126     set | more
127      exit
128     history
129     k
130     env | more
131     set | more
132     more .profile
133     more .profile | grep rof
134     more .profile | grep vi
135     more /etc/profile | grep vi
136     set |grep edit
137     set | grep vi
138     env | grep vi
139     history
140     who
martyp $ set |grep edit
						

Issuing escape 5k fetched the fifth command back in the history list at line 136. This is the same as having issued escape 5-.

You can also move forward in the history list, using j in the same way we used k to move back in the history list. Let's issue escape 5k to move back five commands in the history list to line 136, and then we can use escape 3j to move forward three commands to line 139, as shown in the following example:

martyp $ history
125     man fc
126     set | more
127      exit
128     history
129     k
130     env | more
131     set | more
132     more .profile
133     more .profile | grep rof
134     more .profile | grep vi
135     more /etc/profile | grep vi
136     set |grep edit
137     set | grep vi
138     env | grep vi
139     history
140     history
martyp $ who
						

Issuing escape 3j moved us forward to line 139, which is the same as having issued escape 3-.

We can also go back to the oldest command in the history list with escape G. You can go back to a specific command number from the history list with escape nG, where n is a specific command number from the history file. The following example shows issuing escape 126G to go back to line 126 from the history list:

martyp $ history
125     man fc
126     set | more
127      exit
128     history
129     k
130     env | more
131     set | more
132     more .profile
133     more .profile | grep rof
134     more .profile | grep vi
135     more /etc/profile | grep vi
136     set |grep edit
137     set | grep vi
138     env | grep vi
139     history
140     who
martyp $ set | more
						

You can also recall lines from the history list based on searches. If, for instance, you want to recall the most recently issued command from the history list that has in it profile, you would issue /profile, which is the slash character followed by profile, to get the result shown in the following example:

martyp $ history
125     man fc
126     set | more
127      exit
128     history
129     k
130     env | more
131     set | more
132     more .profile
133     more .profile | grep rof
134     more .profile | grep vi
135     more /etc/profile | grep vi
136     set |grep edit
137     set | grep vi
138     env | grep vi
139     history
140     who
martyp $ more /etc/profile | grep vi
						

Searching for the most recent occurrence of profile produces line 135. Many of the other searches in vi work at the command line. The vi chapter and vi quick reference card have more searching commands that you may want to try at the command line.

Editing on the Command Line Using vi Directives

After you have "fetched" the command you wish to edit or you have entered a command that needs editing, you can use your vi directives to make modifications on the command line.

The ksh puts you in input mode immediately upon fetching a command from the history list. This approach is the converse of the vi program that you use to edit files, which puts you in control mode by default. After you have fetched a command from the history list, you must press escape in order to move into control mode when using vi in ksh.

Let's now perform some simple modifications to commands we have fetched from the history list. We recall line number 286 from the history list with the sequence escape 286G. After recalling this command, we insert cat at the beginning of the command with i cat. i is for insert text to the left of the current cursor position. The following example shows the result of both the fetch of line 286 and inserting cat:

martyp $ history
285     history
286     more /etc/profile | grep vi
287     who
288     whoami
289     who
290     ls -al
291     alias
292     pwd
293     ls -al /home
294     cat .profile
295     history
296     vi .profile
297     cat /etc/passwd
298     cat /etc/passwd | grep donna
299     pwd
300     history
martyp $ cat more /etc/profile | grep vi
						

You can see that i cat inserted cat at the very beginning of the line.

We can again recall line 286 and use A to append text to the very end of the line, as shown in the following example:

martyp $ history
285     history
286     more /etc/profile | grep vi
287     who
288     whoami
289     who
290     ls -al
291     alias
292     pwd
293     ls -al /home
294     cat .profile
295     history
296     vi .profile
297     cat /etc/passwd
298     cat /etc/passwd | grep donna
299     pwd
300     history
martyp $ more /etc/profile | grep vieditor
						

In this example, we used the sequence A editor to insert the word editor at the very end of the command line we had recalled.


We can recall this line and change more at the beginning of the line to cat by issuing the sequence cw cat, as shown in the following example:

martyp $ history
285     history
286     more /etc/profile | grep vi
287     who
288     whoami
289     who
290     ls -al
291     alias
292     pwd
293     ls -al /home
294     cat .profile
295     history
296     vi .profile
297     cat /etc/passwd
298     cat /etc/passwd | grep donna
299     pwd
300     history
martyp $ cat /etc/profile | grep vi
						

This changes more to cat on the command line.

To delete the word more without replacing it, we fetch line 286 and issue dw, as shown in the following example:

martyp $ history
285     history
286     more /etc/profile | grep vi
287     who
288     whoami
289     who
290     ls -al
291     alias
292     pwd
293     ls -al /home
294     cat .profile
295     history
296     vi .profile
297     cat /etc/passwd
298     cat /etc/passwd | grep donna
299     pwd
300     history
martyp $  /etc/profile | grep vi
						

If we are unhappy with the most recent command issued, we can undo the command by issuing u, which undoes the dw we used to remove more on the command line, as shown in the following example:


martyp $ history
285     history
286     more /etc/profile | grep vi
287     who
288     whoami
289     who
290     ls -al
291     alias
292     pwd
293     ls -al /home
294     cat .profile
295     history
296     vi .profile
297     cat /etc/passwd
298     cat /etc/passwd | grep donna
299     pwd
300     history
martyp $ more /etc/profile | grep vi
						

Issuing u puts back the more that we had removed with dw.

You may want to try using both of the vi commands I have covered here, as well as other commands to add, delete, change, search and replace, copy, and undo at the command line.

Aliases in KornShell

An alias is a name that you select for a frequently used command or series of commands. Many aliases are predefined for you.

The alias command, without any arguments, lists all aliases. This list includes both preset aliases as well as those you have set. The following command shows the preset aliases on the system on which I am working:

martyp $ alias
autoload='typeset -fu'
command='command '
functions='typeset -f'
history='fc -l'
hyper1=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc1;export HHLIC'
hyper36=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc36;export HHLIC'
hyper83=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc83;export HHLIC'
hyper95=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc95;export HHLIC'
integer='typeset -i'
local=typeset
nohup='nohup '
r='fc -e -'
stop='kill -STOP'
suspend='kill -STOP $$'
martyp $

Many preset aliases are shown as a result of typing the alias command without any options.

Many of these aliases are related to somewhat advanced use of the KornShell, such as job control. Others are useful to you right away. The history alias, for instance, lists the commands in the .sh_history file and precedes each entry by a line number. The r alias allows you to re-run the the last command that appears in the history list.

You are not limited to using only preset aliases. You can set your own aliases. The following example shows setting an alias, producing a list of aliases to see whether indeed our new alias has been set, and then running our alias:

martyp $ alias ls="ls -al"
martyp $ alias
autoload='typeset -fu'
command='command '
functions='typeset -f'
history='fc -l'
hyper1=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc1;export HHLIC'
hyper36=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc36;export HHLIC'
hyper83=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc83;export HHLIC'
hyper95=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc95;export HHLIC'
integer='typeset -i'
local=typeset
ls='ls -al'
nohup='nohup '
r='fc -e -'
stop='kill -STOP'
suspend='kill -STOP $$'
martyp $ ls
total 26
drwxr-xr-x   2 martyp   staff        512 Mar 15 11:37.
drwxrwxr-x   4 root     sys          512 Mar  4 09:24 ..
-rw-r--r--   1 martyp   staff        124 Mar 15 11:36 .cshrc
-rw-r--r--   1 martyp   staff        562 Mar  4 09:24 .profile
-rw-------   1 martyp   staff       9058 Apr 10 06:58 .sh_history
martyp $

The first command set an alias that executes ls -al whenever we type ls. I issued the alias command to see whether indeed the new alias would appear in the list of aliases. It appears right after local and right before nohup in the alphabetical list of aliases. The final command shows running ls, which produces the same listing that you would receive from running the ls -al command.

You don't have to keep an alias for the duration of your session after having set it. If you don't like an alias, you can use the unalias command to remove an alias.

To see unalias work, let's again produce a list of aliases, use unalias to unset the history alias, run the history command to see whether indeed it has been removed, and then run the fc -l command to which the history alias was mapped:

martyp $ alias
autoload='typeset -fu'
command='command '
functions='typeset -f'
history='fc -l'
hyper1=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc1;export HHLIC'
hyper36=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc36;export HHLIC'
hyper83=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc83;export HHLIC'
hyper95=HHLIC='/opt/local/bristol/hyperhelp/licenses/hpptc95;export HHLIC'
integer='typeset -i'
local=typeset
nohup='nohup '
r='fc -e -'
stop='kill -STOP'
suspend='kill -STOP $$'
martyp $ unalias history
martyp $ history
ksh: history:  not found
martyp $ fc -l
131     ps
132     ls -alF
133     ls -al
134     alias ls="ls -al"
135     alias
136     ls
137     alias
138     unalias ls
139     ls
140     ls -al
141     alias
142     history
143     alias
144     unalias history
145     history
146     fc -l
martyp $

When we unalias history and then run history, ksh is unable to find it and produces the message history: not found. When we run fc -l, a list of the most recently issued commands with their corresponding numbers is produced. This makes it clear that when you run the history alias, you are actually running the fc -l command.

Command and Path Completion

ksh sometimes knows what you're thinking. You can type part of a command or pathname and ksh can complete the remainder for you. You can type part of a command or pathname and press the escape key to complete the command. If, for instance, you wish to issue the uname command to view the current system run level but can't remember the full command, you can type "un" and escape, followed by the "=" key, and the command is completed for you. In the following example, we'll change to the /sbin directory, list its contents, and then type unescape=:

martyp $ cd /sbin
martyp $ ls -al
total 11704
drwxrwxr-x   2 root     sys          512 Nov 27 14:55.
drwxr-xr-x  31 root     root        1024 Apr 19 03:24 ..
-r-xr-xr-x   1 bin      bin       200356 Sep  1  1998 autopush
lrwxrwxrwx   1 root     root          21 Nov 27 14:55 bpgetfile -> ../usr/sbin/e
-r-xr-xr-x   1 bin      bin       470436 Sep  1  1998 dhcpagent
-r-xr-xr-x   1 bin      bin       433064 Sep  1  1998 dhcpinfo
-r-xr-xr-x   1 bin      bin       253664 Sep  1  1998 fdisk
-r-xr-xr-x   1 bin      bin       762816 Sep  1  1998 hostconfig
-r-xr-xr-x   1 bin      bin       535900 Sep  1  1998 ifconfig
-r-xr-xr-x   1 root     sys       516484 Sep  1  1998 init
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 jsh
-r-xr-xr-x   1 bin      bin       224596 Sep  1  1998 mount
-r-xr-xr-x   1 root     sys         6935 Jan  1  1970 mountall
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc0
-rwxr--r--   1 root     sys         2905 Jan  1  1970 rc1
-rwxr--r--   1 root     sys         2491 Jan  1  1970 rc2
-rwxr--r--   1 root     sys         1948 Jan  1  1970 rc3
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc5
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc6
-rwxr--r--   1 root     sys         9412 Jan  1  1970 rcS
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 sh
-r-xr-xr-x   1 bin      bin       195300 Sep  1  1998 soconfig
lrwxrwxrwx   1 root     root          13 Nov 27 14:40 su -> ../usr/bin/su
-r-xr-xr-x   1 root     sys       473808 Sep  1  1998 su.static
-r-xr-xr-x   1 root     bin       288544 Sep  1  1998 sulogin
-rwxr--r--   1 root     sys         3138 Jan  1  1970 swapadd
-r-xr-xr-x   1 bin      bin        29736 Sep  1  1998 sync
-r-xr-xr-x   1 root     sys       435004 Sep  1  1998 uadmin
-r-xr-xr-x   1 bin      bin       213408 Sep  1  1998 umount
-r-xr-xr-x   1 root     sys         3292 Jan  1  1970 umountall
-r-xr-xr-x   1 bin      bin       193152 Sep  1  1998 uname
martyp $ un                                                ;typed unescape=
1) uname
martyp $ un
						

ksh determined that the only command that starts with "un" is uname. The uname command was listed and un was again put at the command prompt for me. You can't see the escape= I typed after the first "un," so I made a comment to the side showing the full command.

Rather than list all files starting with "un," you can replace the current word with all files that match by typing unescape*, as shown in the following example:

martyp $ cd /sbin
martyp $ ls -al
total 11704
drwxrwxr-x   2 root     sys          512 Nov 27 14:55.
drwxr-xr-x  31 root     root        1024 Apr 19 03:24 ..
-r-xr-xr-x   1 bin      bin       200356 Sep  1  1998 autopush
lrwxrwxrwx   1 root     root          21 Nov 27 14:55 bpgetfile -> ../usr/sbin/e
-r-xr-xr-x   1 bin      bin       470436 Sep  1  1998 dhcpagent
-r-xr-xr-x   1 bin      bin       433064 Sep  1  1998 dhcpinfo
-r-xr-xr-x   1 bin      bin       253664 Sep  1  1998 fdisk
-r-xr-xr-x   1 bin      bin       762816 Sep  1  1998 hostconfig
-r-xr-xr-x   1 bin      bin       535900 Sep  1  1998 ifconfig
-r-xr-xr-x   1 root     sys       516484 Sep  1  1998 init
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 jsh
-r-xr-xr-x   1 bin      bin       224596 Sep  1  1998 mount
-r-xr-xr-x   1 root     sys         6935 Jan  1  1970 mountall
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc0
-rwxr--r--   1 root     sys         2905 Jan  1  1970 rc1
-rwxr--r--   1 root     sys         2491 Jan  1  1970 rc2
-rwxr--r--   1 root     sys         1948 Jan  1  1970 rc3
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc5
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc6
-rwxr--r--   1 root     sys         9412 Jan  1  1970 rcS
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 sh
-r-xr-xr-x   1 bin      bin       195300 Sep  1  1998 soconfig
lrwxrwxrwx   1 root     root          13 Nov 27 14:40 su -> ../usr/bin/su
-r-xr-xr-x   1 root     sys       473808 Sep  1  1998 su.static
-r-xr-xr-x   1 root     bin       288544 Sep  1  1998 sulogin
-rwxr--r--   1 root     sys         3138 Jan  1  1970 swapadd
-r-xr-xr-x   1 bin      bin        29736 Sep  1  1998 sync
-r-xr-xr-x   1 root     sys       435004 Sep  1  1998 uadmin
-r-xr-xr-x   1 bin      bin       213408 Sep  1  1998 umount
-r-xr-xr-x   1 root     sys         3292 Jan  1  1970 umountall
-r-xr-xr-x   1 bin      bin       193152 Sep  1  1998 uname
martyp $ uname                                             ;typed unescape*
						

You can see in this example that uname is replaced right at the prompt with the only command that matched unescape*.

The next example shows using umescape= to get a list of all files that start with "um," then using umescape* to get all files matched to "um," and finally, using umescape to replace the current word with the first file name that starts with "um":

martyp $ ls -al
total 11704
drwxrwxr-x   2 root     sys          512 Nov 27 14:55.
drwxr-xr-x  31 root     root        1024 Apr 19 03:24 ..
-r-xr-xr-x   1 bin      bin       200356 Sep  1  1998 autopush
lrwxrwxrwx   1 root     root          21 Nov 27 14:55 bpgetfile -> ../usr/sbin/e
-r-xr-xr-x   1 bin      bin       470436 Sep  1  1998 dhcpagent
-r-xr-xr-x   1 bin      bin       433064 Sep  1  1998 dhcpinfo
-r-xr-xr-x   1 bin      bin       253664 Sep  1  1998 fdisk
-r-xr-xr-x   1 bin      bin       762816 Sep  1  1998 hostconfig
-r-xr-xr-x   1 bin      bin       535900 Sep  1  1998 ifconfig
-r-xr-xr-x   1 root     sys       516484 Sep  1  1998 init
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 jsh
-r-xr-xr-x   1 bin      bin       224596 Sep  1  1998 mount
-r-xr-xr-x   1 root     sys         6935 Jan  1  1970 mountall
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc0
-rwxr--r--   1 root     sys         2905 Jan  1  1970 rc1
-rwxr--r--   1 root     sys         2491 Jan  1  1970 rc2
-rwxr--r--   1 root     sys         1948 Jan  1  1970 rc3
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc5
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc6
-rwxr--r--   1 root     sys         9412 Jan  1  1970 rcS
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 sh
-r-xr-xr-x   1 bin      bin       195300 Sep  1  1998 soconfig
lrwxrwxrwx   1 root     root          13 Nov 27 14:40 su -> ../usr/bin/su
-r-xr-xr-x   1 root     sys       473808 Sep  1  1998 su.static
-r-xr-xr-x   1 root     bin       288544 Sep  1  1998 sulogin
-rwxr--r--   1 root     sys         3138 Jan  1  1970 swapadd
-r-xr-xr-x   1 bin      bin        29736 Sep  1  1998 sync
-r-xr-xr-x   1 root     sys       435004 Sep  1  1998 uadmin
-r-xr-xr-x   1 bin      bin       213408 Sep  1  1998 umount
-r-xr-xr-x   1 root     sys         3292 Jan  1  1970 umountall
-r-xr-xr-x   1 bin      bin       193152 Sep  1  1998 uname
martyp $ um                                                ;typed umescape=
1) umount
2) umountall
martyp $ umount umountall                                  ;typed umescape*
martyp $ umount                                            ;typed umescape
						

Let's now work with a command and arguments that will be file names. What if the characters you type are not unique, as they were with "un" in the /sbin directory? If the command or pathname is not unique, then ksh shows you the options for completing the command. The following example shows typing ls rescape= to get a list of commands that start with "r":

martyp $ ls -al
total 11704
drwxrwxr-x   2 root     sys          512 Nov 27 14:55.
drwxr-xr-x  31 root     root        1024 Apr 19 03:24 ..
-r-xr-xr-x   1 bin      bin       200356 Sep  1  1998 autopush
lrwxrwxrwx   1 root     root          21 Nov 27 14:55 bpgetfile -> ../usr/sbin/e
-r-xr-xr-x   1 bin      bin       470436 Sep  1  1998 dhcpagent
-r-xr-xr-x   1 bin      bin       433064 Sep  1  1998 dhcpinfo
-r-xr-xr-x   1 bin      bin       253664 Sep  1  1998 fdisk
-r-xr-xr-x   1 bin      bin       762816 Sep  1  1998 hostconfig
-r-xr-xr-x   1 bin      bin       535900 Sep  1  1998 ifconfig
-r-xr-xr-x   1 root     sys       516484 Sep  1  1998 init
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 jsh
-r-xr-xr-x   1 bin      bin       224596 Sep  1  1998 mount
-r-xr-xr-x   1 root     sys         6935 Jan  1  1970 mountall
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc0
-rwxr--r--   1 root     sys         2905 Jan  1  1970 rc1
-rwxr--r--   1 root     sys         2491 Jan  1  1970 rc2
-rwxr--r--   1 root     sys         1948 Jan  1  1970 rc3
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc5
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc6
-rwxr--r--   1 root     sys         9412 Jan  1  1970 rcS
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 sh
-r-xr-xr-x   1 bin      bin       195300 Sep  1  1998 soconfig
lrwxrwxrwx   1 root     root          13 Nov 27 14:40 su -> ../usr/bin/su
-r-xr-xr-x   1 root     sys       473808 Sep  1  1998 su.static
-r-xr-xr-x   1 root     bin       288544 Sep  1  1998 sulogin
-rwxr--r--   1 root     sys         3138 Jan  1  1970 swapadd
-r-xr-xr-x   1 bin      bin        29736 Sep  1  1998 sync
-r-xr-xr-x   1 root     sys       435004 Sep  1  1998 uadmin
-r-xr-xr-x   1 bin      bin       213408 Sep  1  1998 umount
-r-xr-xr-x   1 root     sys         3292 Jan  1  1970 umountall
-r-xr-xr-x   1 bin      bin       193152 Sep  1  1998 uname
martyp $ ls r                                            ;typed ls rescape=
1) rc0
2) rc1
3) rc2
4) rc3
5) rc5
6) rc6
7) rcS
martyp $ ls r
						

You can see from this example that typing ls -rescape= produced a list of seven files. Again, the ls r was placed for me at the next prompt. You can use the information left for you at the next prompt to perform additional ksh file name expansion. Let's again perform our ls rescape=, which produces the list of seven files beginning with r. Our next prompt will have ls r waiting for us, and this time we'll type escape*, which will produce a list of all seven files for us on the line:

martyp $ ls -al
total 11704
drwxrwxr-x   2 root     sys          512 Nov 27 14:55.
drwxr-xr-x  31 root     root        1024 Apr 19 03:24 ..
-r-xr-xr-x   1 bin      bin       200356 Sep  1  1998 autopush
lrwxrwxrwx   1 root     root          21 Nov 27 14:55 bpgetfile -> ../usr/sbin/e
-r-xr-xr-x   1 bin      bin       470436 Sep  1  1998 dhcpagent
-r-xr-xr-x   1 bin      bin       433064 Sep  1  1998 dhcpinfo
-r-xr-xr-x   1 bin      bin       253664 Sep  1  1998 fdisk
-r-xr-xr-x   1 bin      bin       762816 Sep  1  1998 hostconfig
-r-xr-xr-x   1 bin      bin       535900 Sep  1  1998 ifconfig
-r-xr-xr-x   1 root     sys       516484 Sep  1  1998 init
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 jsh
-r-xr-xr-x   1 bin      bin       224596 Sep  1  1998 mount
-r-xr-xr-x   1 root     sys         6935 Jan  1  1970 mountall
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc0
-rwxr--r--   1 root     sys         2905 Jan  1  1970 rc1
-rwxr--r--   1 root     sys         2491 Jan  1  1970 rc2
-rwxr--r--   1 root     sys         1948 Jan  1  1970 rc3
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc5
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc6
-rwxr--r--   1 root     sys         9412 Jan  1  1970 rcS
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 sh
-r-xr-xr-x   1 bin      bin       195300 Sep  1  1998 soconfig
lrwxrwxrwx   1 root     root          13 Nov 27 14:40 su -> ../usr/bin/su
-r-xr-xr-x   1 root     sys       473808 Sep  1  1998 su.static
-r-xr-xr-x   1 root     bin       288544 Sep  1  1998 sulogin
-rwxr--r--   1 root     sys         3138 Jan  1  1970 swapadd
-r-xr-xr-x   1 bin      bin        29736 Sep  1  1998 sync
-r-xr-xr-x   1 root     sys       435004 Sep  1  1998 uadmin
-r-xr-xr-x   1 bin      bin       213408 Sep  1  1998 umount
-r-xr-xr-x   1 root     sys         3292 Jan  1  1970 umountall
-r-xr-xr-x   1 bin      bin       193152 Sep  1  1998 uname
martyp $ ls r                                            ;typed ls rescape=
1) rc0
2) rc1
3) rc2
4) rc3
5) rc5
6) rc6
7) rcS
martyp $ ls rc0 rc1 rc2 rc3 rc5 rc6 rcS
                                      ;typed escape*
							to get seven files
						

escape* listed all seven files beginning with r and placed them on the command line.

In the next example we'll issue both the escape= and escape*. We'll then type ls escape_ (underscore), which puts the last word of the last command in the line, which is rcS:

martyp $ ls -al
total 11704
drwxrwxr-x   2 root     sys          512 Nov 27 14:55.
drwxr-xr-x  31 root     root        1024 Apr 19 03:24 ..
-r-xr-xr-x   1 bin      bin       200356 Sep  1  1998 autopush
lrwxrwxrwx   1 root     root          21 Nov 27 14:55 bpgetfile -> ../usr/sbin/e
-r-xr-xr-x   1 bin      bin       470436 Sep  1  1998 dhcpagent
-r-xr-xr-x   1 bin      bin       433064 Sep  1  1998 dhcpinfo
-r-xr-xr-x   1 bin      bin       253664 Sep  1  1998 fdisk
-r-xr-xr-x   1 bin      bin       762816 Sep  1  1998 hostconfig
-r-xr-xr-x   1 bin      bin       535900 Sep  1  1998 ifconfig
-r-xr-xr-x   1 root     sys       516484 Sep  1  1998 init
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 jsh
-r-xr-xr-x   1 bin      bin       224596 Sep  1  1998 mount
-r-xr-xr-x   1 root     sys         6935 Jan  1  1970 mountall
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc0
-rwxr--r--   1 root     sys         2905 Jan  1  1970 rc1
-rwxr--r--   1 root     sys         2491 Jan  1  1970 rc2
-rwxr--r--   1 root     sys         1948 Jan  1  1970 rc3
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc5
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc6
-rwxr--r--   1 root     sys         9412 Jan  1  1970 rcS
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 sh
-r-xr-xr-x   1 bin      bin       195300 Sep  1  1998 soconfig
lrwxrwxrwx   1 root     root          13 Nov 27 14:40 su -> ../usr/bin/su
-r-xr-xr-x   1 root     sys       473808 Sep  1  1998 su.static
-r-xr-xr-x   1 root     bin       288544 Sep  1  1998 sulogin
-rwxr--r--   1 root     sys         3138 Jan  1  1970 swapadd
-r-xr-xr-x   1 bin      bin        29736 Sep  1  1998 sync
-r-xr-xr-x   1 root     sys       435004 Sep  1  1998 uadmin
-r-xr-xr-x   1 bin      bin       213408 Sep  1  1998 umount
-r-xr-xr-x   1 root     sys         3292 Jan  1  1970 umountall
-r-xr-xr-x   1 bin      bin       193152 Sep  1  1998 uname
martyp $ ls r                                    ;typed ls rescape=
1) rc0
2) rc1
3) rc2
4) rc3
5) rc5
6) rc6
7) rcS
martyp $ ls rc0 rc1 rc2 rc3 rc5 rc6 rcS         ;typed escape* to get seven files
rc0  rc1  rc2  rc3  rc5  rc6  rcS
martyp $ ls  rcS                                ;typed lsescape_ to get last word
rcS
martyp $

Now that we've seen how to get the last of the words to appear on the command line with escape_, how about the third word of the last command? You can specify the third word by typing escape3_ or substitute for the "3" for any of the words on the last command line. The following example shows listing the third word of the last command:

martyp $ ls -al
total 11704
drwxrwxr-x   2 root     sys          512 Nov 27 14:55.
drwxr-xr-x  31 root     root        1024 Apr 19 03:24 ..
-r-xr-xr-x   1 bin      bin       200356 Sep  1  1998 autopush
lrwxrwxrwx   1 root     root          21 Nov 27 14:55 bpgetfile -> ../usr/sbin/e
-r-xr-xr-x   1 bin      bin       470436 Sep  1  1998 dhcpagent
-r-xr-xr-x   1 bin      bin       433064 Sep  1  1998 dhcpinfo
-r-xr-xr-x   1 bin      bin       253664 Sep  1  1998 fdisk
-r-xr-xr-x   1 bin      bin       762816 Sep  1  1998 hostconfig
-r-xr-xr-x   1 bin      bin       535900 Sep  1  1998 ifconfig
-r-xr-xr-x   1 root     sys       516484 Sep  1  1998 init
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 jsh
-r-xr-xr-x   1 bin      bin       224596 Sep  1  1998 mount
-r-xr-xr-x   1 root     sys         6935 Jan  1  1970 mountall
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc0
-rwxr--r--   1 root     sys         2905 Jan  1  1970 rc1
-rwxr--r--   1 root     sys         2491 Jan  1  1970 rc2
-rwxr--r--   1 root     sys         1948 Jan  1  1970 rc3
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc5
-rwxr--r--   3 root     sys         2689 Jan  1  1970 rc6
-rwxr--r--   1 root     sys         9412 Jan  1  1970 rcS
-r-xr-xr-x   2 bin      root      257444 Sep  1  1998 sh
-r-xr-xr-x   1 bin      bin       195300 Sep  1  1998 soconfig
lrwxrwxrwx   1 root     root          13 Nov 27 14:40 su -> ../usr/bin/su
-r-xr-xr-x   1 root     sys       473808 Sep  1  1998 su.static
-r-xr-xr-x   1 root     bin       288544 Sep  1  1998 sulogin
-rwxr--r--   1 root     sys         3138 Jan  1  1970 swapadd
-r-xr-xr-x   1 bin      bin        29736 Sep  1  1998 sync
-r-xr-xr-x   1 root     sys       435004 Sep  1  1998 uadmin
-r-xr-xr-x   1 bin      bin       213408 Sep  1  1998 umount
-r-xr-xr-x   1 root     sys         3292 Jan  1  1970 umountall
-r-xr-xr-x   1 bin      bin       193152 Sep  1  1998 uname
martyp $ ls r                                    ;typed ls rescape=
1) rc0
2) rc1
3) rc2
4) rc3
5) rc5
6) rc6
7) rcS
martyp $ ls rc0 rc1 rc2 rc3 rc5 rc6 rcS       ;typed escape* to get seven files
rc0  rc1  rc2  rc3  rc5  rc6  rcS
martyp $ ls  rc1                            ;typed lsescape3_ to get third word

Because the previous command included the ls command, the third word is not rc2 but rc1, because ls was the first entry in the previous command.

The Table 27-1 summarizes the command and path completion used in the previous examples:

Table 27-1. Command and Path Completion in ksh
Word or Command (type escape before each)Result
wordescape=Displays a numbered list of file names beginning with word.
wordescape*Replaces word with all files matched.
wordescapeReplaces word with the first file name that starts with word.
command wordescape=Displays a numbered list of file names beginning with word.
command wordescape*Replaces word with all files matched.
command wordescape_Inserts the last word of the last command at the cursor position.
command wordescape_3Inserts the third word of the last command at the cursor position.

File Name Expansion

In your general activities working with ksh, you have to perform a lot of file-name-related work, including crafting shell scripts that deal with file names. An overview of file name expansion is useful to ensure that you're comfortable with this topic before you start writing shell scripts.

Table 27-2 lists some common filename expansion and pattern matching commands:

Table 27-2. File Name Expansion and Pattern Matching
Character(s)ExampleDescription
*1) ls *.cMatch zero or more characters
?2) ls conf.?Match any single character
[list]3) ls conf.[co]Match any character in list
[lower-upper]4) ls libdd.9873[5-6].slMatch any character in range
str{str1,str2,str3,...}5) ls ux*.{700,300}Expand str with contents of {}
~6) ls -a ~Home directory
~username7) ls -a ~geneHome directory of username

The following are more detailed descriptions of the examples shown in Table 27-2:

  1. To list all files in a directory that end in ".c," you could do the following:


    ls *.c
            conf. SAM.c conf.c

  2. To find all the files in a directory named "conf" with an extension of one character, you could do the following:


    ls conf.?
           conf.c conf.o conf.1

  3. To list all the files in a directory named "conf" with only the extension "c" or "o," you could do the following:


    ls conf.{co}
           conf.c conf.o

  4. To list files with similar names but with a specific field that covers a range, you could do the following:


    ls libdd9873[5-6].sl
            libdd98735.sl libdd98736.sl

  5. To list files that start with "ux" and have the extension "300" or "700," you could do the following:


    ls ux*.{700,300}
           uxbootlf.700 uxinstfs.300

  6. To list the files in your home directory, you could use ~:


    ls -a ~
           .    .cshrc.org .login    .shrc.org
           ..   .exrc    .login.org    .cshrc
           .history

  7. To list the files in the home directory of a user, you can do the following:


    ls -a ~gene
           .      .history   splinedat under.des
           ..     .login    trail.txt xtra.part
           .chsrc   .login.org ESP-File
           .cshrc.org .profile Mail
           .exrc    .shrc.org opt

Many of these techniques are useful when working with ksh and writing shell scripts, so you want to become familiar with file name expansion.

Redirection (I/O Redirection)

UNIX is set up such that commands usually take their input from the keyboard, often called standard input, and usually send output to the screen, often called standard output. Commands also send error information to the screen. You do not always want input to come from standard input and output and errors to go to standard output. You are given a lot of control to override these defaults. This is called redirection. Table 27-3 shows many common forms of redirection.

As shown in Table 27-3, to redirect the output of a command from standard output to a file, you use ">". This works almost all of the time. If you have an environment variable called noclobber set, then redirecting to an existing file does not work (we'll cover environment variables shortly). The noclobber does not permit redirection to write over an existing file. If you try to write over an existing file, such as /tmp/processes below, you receive a message that the file exists:

#  ps  -ef  > /tmp/processes
/tmp/processes:  File exists

You can, however, use a "!" with redirection to force a file to be overwritten. Using ">!" forces a file to be overwritten, and ">>!" forces the output to be appended to the end of an existing file. Examples of these are shown in Table 27-3.

Table 27-3. Commonly Used Redirection Forms
Command or AssignmentExampleDescription
<wc -l < .loginStandard input redirection: execute wc (word count) and list number of lines (-l) in .login
>ps -ef > /tmp/processesStandard output redirection: execute ps and send output to file /tmp/processes
>>ps -ef >> /tmp/processesAppend standard output: execute ps and append output to the end of file /tmp/processes
>!ps -ef >! /tmp/processesStandard output redirection and override noclobber: write over /tmp/processes even if it exists
>>!ps -ef >>! /tmp/processesAppend standard output and override noclobber: append to the end of /tmp/processes
| (pipe)ps | wc -lRun ps and use the result as input to wc
0 - standard input  
1 - standard output  
2 - standard errorcat program 2> errorscat the file program to standard output and redirect errors to the file errors
 cat program 2>> errorscat the file program to standard output and append errors to the file errors
 find / -name '*.c' -print > cprograms 2>errorsfind all files on the system ending in .c, place the list of files in cprograms in the current working directory, and send all errors (file descriptor 2) to the file errors in current working directory
 find / -name '*.c' -print > cprograms 2>&1find all files on the system ending in .c, place the list of files in cprograms in the current working directory, and send all errors (file descriptor 2) to same place as file descriptor 1 (cprograms)

Environment Variables

An environment variable is a name associated with a string. The name is the variable and the string is its value. Environment variables are also available to sub-shells or processes spawned by the shell. In most cases, you see environment variables capitalized, which is the convention on most systems.

When you issue a command on the system, you usually enter a relative pathname, not an absolute pathname. The command you issue is found because the PATH variable points to the location of directories where commands are located. Without this PATH variable, you would have to type the absolute pathname of every command you issue. When you issue a command, the shell searches the directories listed in the PATH variable in the order in which they are listed. A good way to see many of the environment variables you have set is with the env command as shown below:

martyp $ env
_=/usr/bin/env
MANPATH=:/opt/local/ptc/sysadmin/scripts:/opt/local/ptc/man:/opt/local/altrasofn
_INIT_UTS_RELEASE=5.7
HZ=100
_INIT_UTS_MACHINE=sun4m
EPC=true
PATH=/usr/bin:/usr/ucb:/etc:.
WEB_SERVER=sioux.rose.hp.com
_INIT_UTS_VERSION=Generic
MODEL=SPARCstation-10
OS_REV=5.7
EDITOR=vi
_INIT_RUN_NPREV=0
CLASSPATH=.:/usr/java/lib:
LOGNAME=martyp
_INIT_UTS_NODENAME=sunsys
_INIT_UTS_ISA=sparc
MAIL=/var/mail/martyp
ERASE=^H
OS=solaris
PS1=$PWD
$LOGNAME $TOKEN
_INIT_PREV_LEVEL=S
HOST=sunsys
TESTEXPERT_HOME=/opt/local/svn/te33
TA_HOME=/opt/local/platinum/solaris2/testadvise
MA_HOME=/opt/local/platinum/solaris2/memadvise
CL_LICENSE_FILE=/opt/local/CenterLine/configs/license.dat
SHELL=/bin/ksh
PROFILE_DIR=/opt/local/ptc/sysadmin/profile.d
OSTYPE=solaris2
HOME=/home/martyp
_INIT_UTS_SYSNAME=SunOS
TERM=vt100
LD_LIBRARY_PATH=:/opt/local/parasoft/lib.solaris
MWHOME=/opt/local/mainsoft/mainwin/mw
FMHOME=/opt/local/adobe/frame
PWD=/home/martyp
TZ=US/Pacific
_INIT_RUN_LEVEL=3
CLEARCASE_BLD_UMASK=02
_INIT_UTS_PLATFORM=SUNW,SPARCstation-10
martyp $

As you can see, other environment variables in addition to PATH make working on your UNIX system easier. You may want to issue other commmands related to ksh variables. Table 27-4 summarizes some ksh-related variable commands you may want to issue on your system.

Table 27-4. ksh-Related Variable Commands
CommandDescription
envLists all environment variables (exported). These variables are normally uppercase and passed to child processes.
setPrints all local and exported set variables.
set -oLists all built-in variables that are set to on or off.
typesetDisplays all variables and associated attributes, functions, and integers.
typeset +Displays only the names of variables.

You may want to try all these commands on your system to see what variables have been set for you.

If you want to know the value of a specific environment variable, you could use the echo command to see its value, as shown below for the environment variable HOME:

martyp $ echo $HOME
/home/martyp

Similarly, to view the operating system type on this specific computer, you could issue the following command:

martyp $ echo $OSTYPE
solaris2

The "$" preceding the environment variable name specifies that the value of the variable be sent to standard output. In this case, the value of the environment variable HOME is /home/martyp, which means that the current user has a home directory of /home/martyp.

You can define your own environment variables in ksh with the following syntax:

export NAME=value
						

Many users like to customize the ksh prompts. Most systems provide four ksh prompts by default. You can normally modify the first two prompts. The first, called PS1, is the primary prompt. The second, called PS2, appears after you have partially typed a command and pressed enter. PS1 is normally set to a $ and PS2 to >, by default.

The following example sets PS1 to our home directory, a space, the current history number, a space, and dollar sign:

							PS1="`pwd` ! $ "
						

We'll leave the default for PS2 as >. The following sequence shows issuing a command at our new PS1 prompt and the default PS2 prompt:

/home/martyp 187 $ print "This is new PS1
> but default PS2"
This is new PS1
but default PS2
/home/martyp 188 $

This example shows the new PS1, including the history entry incrementing from 187 to 188, and the default PS2 when the incomplete print command was issued.

You can also append to the end of an existing variable with the following format:

export NAME="$NAME:appended_information"
						

To add /home/martyp/programs to the existing PATH environment variable, for instance, you issue the following command:

							export PATH="$PATH:/home/martyp/programs"
						

This appends the path /home/martyp/programs to the environment variable PATH.

A great deal of flexibility is available when working with ksh. You should view all your variables and update those that make your job easier. Some customization, such as updating PS1 and your PATH, can also make your job easier.

Background Jobs and Job Control

When you run a command, as we have done so far in many examples, you don't get back the prompt until the command has completed. These commands have been run in the foreground. Some commands can take a long time to complete, in which case, you'll be waiting a long time for the prompt to return. As an alternative to waiting for the prompt to return, you can run the command in the background, meaning that it is running behind the scenes while you perform other work. Because UNIX is multi-tasking it is happy to run many commands in the background and still provide you with a prompt to issue yet more commands.

In order to run a command in the background, you simply add an ampersand (&) to the end of the command line. When you follow your command with an ampersand, the command is run in the background and the prompt is immediately returned.

Let's now run some commands on our Solaris system. We'll first run a command to find all of the files in /usr that end in ".c," which takes some time to complete. We'll preface the find string with the time command so that we know how long the command takes to complete:


martyp $ time find /usr -name *.c
             .
             .
             .
/usr/demo/link_audit/src/dumpbind.c
/usr/demo/link_audit/src/env.c
/usr/demo/link_audit/src/hash.c
/usr/demo/link_audit/src/perfcnt.c
/usr/demo/link_audit/src/symbindrep.c
/usr/demo/link_audit/src/truss.c
/usr/demo/link_audit/src/who.c
find: cannot read dir /usr/aset: Permission denied

real    1m21.04s
user    0m1.51s
sys     0m12.67s

This commad took roughly one minute and 21 seconds to complete. Because it was run in the foreground we were unable to issue any other commands while it was running, because we had to wait for the prompt to return.

An alternative to running the command in the foreground is to issue the command followed by an ampersand, in which case the job runs in the background and the prompt returns immediately, as shown in the following example:

martyp $ time find /usr -name *.c > cprogs 2>&1 &
[3]     16279
martyp $
real    2m10.20s
user    0m1.31s
sys     0m8.62s

The result of running this command in the background produces a job number in brackets and the process id, or PID, as the second number. All the outputs of this command, including errors, are written to the file cprogs. The prompt was immediately returned after we issued the command, and after it completed, the output of time was sent to the screen. We could have begun issuing additional commands immediately after issuing the command in the background.

You have control over both foreground jobs and background jobs. To suspend a foreground job, you type the "control" and "z" keys simultaneously, as shown in the following example:


martyp $ find /usr -name *.c
/usr/openwin/share/include/X11/Xaw/Template.c
/usr/openwin/share/src/dig_samples/DnD/main.c
/usr/openwin/share/src/dig_samples/DnD/owner.c
/usr/openwin/share/src/dig_samples/DnD/requestor.c
/usr/openwin/share/src/dig_samples/Tooltalk/olit_tt.c
/usr/openwin/share/src/dig_samples/Tooltalk/tt_callbacks.c
/usr/openwin/share/src/dig_samples/Tooltalk/tt_code.c
/usr/openwin/share/src/dig_samples/ce1/ce_map1.c
/usr/openwin/share/src/dig_samples/ce2/ce_simple.c
/usr/openwin/share/src/dig_samples/dnd_olit/olitdnd.c
/usr/openwin/share/src/dig_samples/dnd_xview1/xview_dnd.c
/usr/openwin/share/src/dig_samples/dnd_xview2/
xview_dnd2.c
/usr/openwin/share/src/dig_samples/selection_olit/olit_sel.c
/usr/openwin/share/src/dig_samples/tooltalk_simple/ttsend.c
/usr/openwin/share/src/olit/oldials/oldials.c
/usr/openwin/share/src/olit/olitbook/ch10/draw.c
^Z[3] + Stopped (SIGTSTP)        find /usr -name *.c

After ctrl-z is pressed, the find command is interrupted at the point at which you type ctrl-z. The command is suspended at this point, and you are shown the job number, in this case "3," and its status is listed as "Stopped". This command has only been suspended; it is not gone forever. You can start this process in the foreground with fg, or run it in the background with bg. Using bg runs the command as if you had followed it with an "&". It is started from the point at which you interrupted it. You do not have to supply a job number when you issue the fg or bg command, because the default is to perform the specified operation on the last job, which in this case is job number 3.

Notice that in this example we have stopped job number 3. This means that there are other jobs running with lower job numbers. You can use the jobs command to get a list of all jobs and their status. You can then control the jobs by issuing commands such as fg followed by a "%" and the job number to run the command in the foreground, or a bg followed by a "%" and the job number to run the command in the background. If you wish to terminate a job altogether, you can issue the kill command followed by a "%" and the job number.

In the process of creating the examples in this section, I have started and suspended many jobs. The following example shows listing all jobs with the jobs command, killing jobs 1 and 2 with kill, and running job 3 in the background:

martyp $ jobs
[3] + Stopped (SIGTSTP) find /usr -name *.c
[2] - Running         time find / -name gnu* > gnu 2>&1 &
[1]   Running            time find / -name *.c > cprogs 2>&1 &
martyp $ kill %1
[1]   Terminated         time find / -name *.c > cprogs 2>&1 &
martyp $ kill %2
[2] - Terminated      time find / -name gnu* > gnu 2>&1 &
martyp $ bg %3
[3]     find /usr -name *.c&
martyp $

Notice that an ampersand was added to job 3 when we requested that it be run in the background. Killing jobs 1 and 2 and running job 3 in the background returns the prompt so that you can perform additional work.

umask and Permissions

An additional topic to cover related to ksh is file permissions and the way they relate to umask. This is important because you may write shell programs, and the permissions control the access that others will have to these programs. umask is used to specify permission settings for new files and directories.

Let's start with an example of a long listing of a file. We'll use ls -l in the following example:

sys1 1: ls -l script1
-rwxr-xr-x  1  marty  users  120 Jul 26 10:20 script1

The access rights for this file are defined by the position of read (r), write (w), and execute (x) when the ls -l command is issued. Figure 27-1 shows the three groups of three access rights for this file:

Figure 27-1. Example of File Permissions


The owner of this file has read, write, and execute permissions on the file. The group to which the user belongs has read and execute permissions, and others also have read and execute permissions. The permissions on this file can be specified by the octal sum of each field, which is 755.

What happens if you craft a new shell script or any new file? What permission settings exist? You want to execute the shell script, so you need execute permission for the file. You can use umask to define the defaults for all your new files and directories.

By default, most systems start with a permission of 777 for directories and 666 for files. These mean that everyone has complete access to all directories you create and everyone has read and write access to all files you create. These defaults are modified with the value of umask.

You can view your umask in the following two ways:

martyp $ umask
002
martyp $ umask -S
u=rwx,g=rwx,o=rx
martyp $

The first example displays the octal value of umask, which we'll cover shortly, and the second example shows the symbolic value of umask.

The umask is used to disable access. You start with a umask and use the fields to disable some level of access. The umask command uses three octal fields. The fields are the sum of the access codes for user, group, and other as shown in Figure 27-2:

Figure 27-2. umask Fields


The complement of the umask field is "anded" with the default setting to change the umask. You can set umask by specifying its value. In our earlier example we viewed umask two different ways. To set the umask, you simply issue umask and the desired value. Setting umask to 022, for example, removes write permissions of directories for "group" and "other," as shown in Figure 27-3:

Figure 27-3. umask Example


umask 022 changes the directory permissions to 755 in this example.

Similarly, a umask of 022 changes the default permission of 666 for files to 644, which would be read-only for group and other.

Change File Permissions with chmod

The chmod command is used to change the permissions on a file. Irrespective of what takes place with umask as just described, you can change a file's permissions at any time with chmod. You need to be the owner of the file or superuser to change a file's permissions with chmod in most cases. Let's start our discussion of chmod with the listing of the file sort:

$ ls -l sort
-rwxr-x--x   1 marty     users     120 Jul 26 10:20 sort

Figure 27-4 shows a breakdown of the permissions on sort:

Figure 27-4. Permissions of File sort


You have very little control over the type of file defined. You do, however, have a great deal of control over the permissions of this file if it belongs to you. The chmod command is used to change the permissions on a file or directory. If you are the owner of the file, you can have a field day changing the permissions on the file.

Two means exist by which you can change the permissions: symbolic and numeric. I focus first on the numeric mode, because the numbers involved are easy to manage, and I sometimes find that new UNIX users get hung up on the meanings of some of the symbols. I'll then cover the symbols and include the symbol meanings in the chmod summary.

First of all, what do I mean by numbers? Looking at the numbers for sort, we see permissions of 751: 7 for owner (hundred's position), 5 for group (ten's position), and 1 for other (one's position). Figure 27-5 helps with the meanings of the positions:

Figure 27-5. Numerical Permissions Summary


Selecting the desired permissions for owner, group, and other, you use the chmod command to assign those permissions to a file or directory. Some of these permission possibilities are infrequently used, such as execute only, because you usually need to have read access to a file in order to execute it; however, I included all possibilities in Figure 27-5 for completeness. In addition to the permission mode bits shown in Figure 27-5, there are also miscellaneous mode bits, which you don't need to be concerned with at this time.

If you decide that you would like to add write permission of the file sort for group, and remove all permissions for other, you would simply execute the chmod command with the appropriate numeric value. The following set of commands first list the existing permissions for sort, next change the permissions on sort, and finally, list the new permissions on sort:

$ ls -l sort
-rwxr-x--x   1 marty     users     120 Jul 26 10:20 sort

$ chmod 770 sort

$ ls -l sort
-rwxrwx---   1 marty     users     120 Jul 26 10:20 sort

The same set of commands to change the permissions using the symbolic mode would be:

$ ls -l sort
-rwxr-x--x   1 marty     users     120 Jul 26 10:20 sort

$ chmod g+w,o-x sort

$ ls -l sort
-rwxrwx---   1 marty     users     120 Jul 26 10:20 sort

In symbolic mode, you issue the chmod command and specify who will be affected by the change [user (u), group (g), other (o), or all (a)], the operation you wish to perform [add (+), delete (-), or replace (=)], and the permission you wish to specify [read (r), write (w), or execute (x)]. In the previous example using symbolic mode, write (w) permission is being added (+) for group (g), and execute (x) permission is being removed (-) for other (o).

The following is a summary of some of the more commonly used symbols of chmod:

chmod - Change permissions of specified files using the following symbolic mode list.

Symbol of who is affected:
 uUser is affected.
 gGroup is affected.
 oOther is affected.
 aAll users are affected.
Operation to perform:
 +Add permission.
 -Remove permission.
 =Replace permission.
Permission specified:
 rRead permission.
 wWrite permission.
 xExecute permission.
 uCopy user permissions.
 gCopy group permissions.
 oCopy other permissions.

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

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