CONTENTS |
Before the Korn shell displays a prompt, it is preceded by a number of processes. See Figure 10.1.
The first process to run is called init, PID 1. It gets instructions from a file called inittab (System V) or spawns a getty (BSD) process. These processes open up the terminal ports, provide a place where input comes from, stdin, and the place where standard output (stdout) and standard error (stderr) go, and put a login prompt on your screen. The /bin/login program is then executed. The login program prompts you for a password, encrypts and verifies the password, sets up an initial environment, and starts up the login shell, /bin/ksh, the last entry in the passwd file. The ksh program looks for the system file, /etc/profile, and executes its commands. It then looks in the user's home directory for an initialization file called .profile, and an environment file, conventionally called .kshrc. After executing commands from those files, the dollar sign prompt appears on your screen and the Korn shell awaits commands.
The Initialization Files. After executing the commands in /etc/profile, the initialization files in the user's home directory are executed. The .profile is executed, followed by the ENV file, commonly called the .kshrc file.
The /etc/profile File. The /etc/profile is a systemwide readable file set up by the system administrator to perform tasks when the user logs on and the Korn shell starts up. It is available to all Bourne and Korn shell users on the system, and normally performs such tasks as checking the mail spooler for new mail and displaying the message of the day from the /etc/motd file. The following text is an example of the /etc/profile. See Chapter 8, "The Interactive Bourne Shell," for a complete explanation of each line of /etc/profile.
EXAMPLE # The profile that all logins get before using their own .profile trap " " 2 3 export LOGNAME PATH # Initially set by /bin/login if [ "$TERM" = " " ] then if /bin/i386 then # Set the terminal type TERM=AT386 else TERM=sun fi export TERM fi # Login and -su shells get /etc/profile services. # -rsh is given its environment in the .profile. case "$0" in -sh | -ksh | -jsh ) if [ ! -f .hushlogin ] then /usr/sbin/quota # Allow the user to break the Message-Of-The-Day only. trap "trap ' ' 2" 2 /bin/cat -s /etc/motd # Display the message of the day trap " " 2 /bin/mail -E case $? in 0) # Check for new mail echo "You have new mail. " ;; 2) echo "You have mail. " ;; esac fi esac umask 022 trap 2 3
The .profile File. The .profile file is a user-defined initialization file, that is executed once at login (by the Bourne and Korn shells) and is found in your home directory. It gives you the ability to customize and modify your working environment. Environment variables and terminal settings are normally set here, and if a window application or dbm is to be initiated, it is started here. If the .profile file contains a special variable called ENV, the filename that is assigned to that variable will be executed next. The ENV file is often named .kshrc; it contains aliases and set o commands. The ENV file is executed every time a ksh subshell is spawned. The lines from the following files may not be meaningful to you now, but all of the concepts, such as exporting variables, history, the search path, and so on, will be discussed in detail throughout the text of this book.
1 set -o allexport 2 TERM=vt102 3 HOSTNAME=$(uname -n) 4 HISTSIZE=50 5 EDITOR=/usr/ucb/vi 6 ENV=$HOME/.kshrc 7 PATH=$HOME/bin:/usr/ucb:/usr/bin:\ /usr/local:/etc:/bin:/usr/bin:/usr/local\ /bin:/usr/hosts:/usr/5bin:/usr/etc:/usr/bin:. 8 PS1="$HOSTNAME ! $ " 9 set +o allexport 10 alias openwin=/usr/openwin/bin/openwin 11 trap '$HOME/.logout' EXIT 12 clear
EXPLANATION
|
The ENV File. The ENV variable is assigned the name of a file that will be executed every time an interactive ksh or ksh program (script) is started. The ENV variable is set in the .profile and is assigned the name of the file that will contain special ksh variables and aliases. The name is conventionally .kshrc, but you can call it anything you want. (The ENV file is not processed when the privileged option is on. See Table 10.1.)
1 set -o trackall 2 set -o vi 3 alias l='ls -laF' alias ls='ls -aF' alias hi='fc -l' alias c=clear 4 function pushd { pwd > $HOME/.lastdir.$$ ; } function popd { cd $(< $HOME/.lastdir.$$) ; rm $HOME/.lastdir.$$; pwd; } function psg { ps -ef | egrep $1 | egrep -v egrep; } function vg { vgrind -s11 -t $* | lpr -t ; }
EXPLANATION
|
The set o Options. The set command can take options if the o switch is used. Options allow you to customize the shell environment. They are either on or off, and are normally set in the ENV file.
FORMATset -o option Turns on the option. set +o option Turns off the option set -[a-z] Abbreviation for an option; the minus turns it on set +[a-z] Abbreviation for an option; the plus turns it off |
set -o allexport set +o allexport set -a set +a
EXPLANATION
|
Name of Option | Abbreviation | What It Does |
---|---|---|
allexport | a | Causes variables set to be automatically exported. |
bgnice | Background jobs are run with a lower priority. | |
emacs | For command line editing, uses the emacs built-in editor. | |
errexit | e | If a command returns a nonzero exit status (fails), executes the ERR trap, if set, and exits. Not set when reading initialization files. |
gmacs | For command editing, uses the gmacs built-in editor. | |
ignoreeof | Prevents logout with ^D; must type exit to exit the shell. | |
markdirs | Puts a trailing backslash (/) on directory names when filename expansion is used. | |
monitor | m | Allows job control. |
noclobber | Protects files from being overwritten when redirection is used. | |
noexec | n | Reads commands, but does not execute them. Used to check the syntax of scripts. Not on when running interactively. |
noglob | f | Disables pathname expansion; i.e., turns off wildcards. |
nolog | Does not store function definitions in the history file. | |
notify | Notifies user when background job finishes (only in versions newer than 1988). | |
nounset | Displays an error when expanding a variable that has not been set. | |
privileged | p | When set, the shell does not read the .profile or ENV file; used with setuid scripts. |
trackall | Enables alias tracking. | |
verbose | v | Turns on the verbose mode for debugging. |
vi | For command line editing, uses the vi built-in editor. | |
xtrace | x | Turns on the echo mode for debugging. |
The Korn shell provides four prompts.The primary and secondary prompts are used when the Korn shell is running interactively. You can change these prompts. The variable PS1 is the primary prompt, set initially to a dollar sign ($). It appears when you log on and waits for you to type commands. The variable PS2 is the secondary prompt, initially set to the > character. It appears if you have partially typed a command and then pressed Enter. You can change the primary and secondary prompts.
The Primary Prompt. $ is the default primary prompt. You can change your prompt. Normally, prompts are defined in .profile.
1 $ PS1="$(uname n) ! $ " 2 jody 1141 $
EXPLANATION
|
The Secondary Prompt. The PS2 prompt is the secondary prompt. Its value is displayed to standard error (the screen). This prompt appears when you have not completed a command and have pressed the carriage return.
1 $ print "Hello 2 > there" 3 Hello there 4 $ 5 $ PS2=" > " 6 $ print "Hi 7 > > > there" Hi there $
EXPLANATION
|
To execute a command typed at the command line or within a shell script, the Korn shell searches the directories listed in the PATH variable. The PATH is a colon-separated list of directories, searched by the shell from left to right. The dot in the PATH represents the current working directory. If the command is not found in any of the directories listed in the path, the shell sends the message ksh: filename: not found to standard error. It is recommended that the path be set in the .profile file. To speed up the searching process, the Korn shell has implemented tracked aliases. See "Tracked Aliases" on page 455.
$ echo $PATH /home/gsa12/bin:/usr/ucb:/usr/bin:/usr/local/bin:.
EXPLANATIONThe Korn shell will search for commands starting in /home/gsa12/bin. If the command is not found there, /usr/ucb is searched, then /usr/bin, /usr/local/bin, and finally the user's home directory represented by the period. |
The Dot Command. The dot command (.) is a built-in Korn shell command. It takes a scriptname as an argument. The script will be executed in the environment of the current shell. A child process will not be started. The dot command is normally used to reexecute the .profile file or the ENV file, if either of those files has been modified. For example, if one of the settings in either file has been changed after you have logged on, you can use the dot command to reexecute the initialization files without logging out and then logging back in.
$ . .profile $ . .kshrc $ . $ENV
EXPLANATIONNormally a child process is started when commands are executed. The dot command executes each of the initialization files, .profile, the ENV file (.kshrc), in the current shell. Local and global variables in these files are defined within this shell. Otherwise, the user would have to log out and log back in to cause these files to be executed for the login shell. The dot command makes that unnecessary. |
After logging in, the Korn shell displays its primary prompt, a dollar sign by default. The shell is your command interpreter. When the shell is running interactively, it reads commands from the terminal and breaks the command line into words. A command line consists of one or more words (or tokens), separated by whitespace (blanks and/or tabs), and terminated with a newline, generated by pressing Enter. The first word is the command, and subsequent words are the command's arguments. The command may be a UNIX executable program such as ls or pwd, a built-in command such as cd or jobs, or a shell script. The command may contain special characters, called metacharacters, which the shell must interpret while parsing the command line. If a command line is too long, the backslash character, followed by a newline, will allow you to continue typing on the next line. The secondary prompt will appear until the command line is terminated.
The Order of Processing Commands. The first word on the command line is the command to be executed. The command may be a keyword, a special built-in command or utility, a function, a script, or an executable program. The command is executed according to its type in the following order:[1]
Keyword (such as if, while, until).
Aliases (see typeset f).
Built-in commands.
Functions.
Scripts and executables.
The special built-in commands and functions are defined within the shell, and therefore are executed from within the current shell, making them much faster in execution. Scripts and executable programs such as ls and pwd are stored on disk, and the shell must locate them within the directory hierarchy by searching the PATH environment variable; the shell then forks a new shell that executes the script. To find out the type of command you are using, use the built-in command, whence v , or its alias, type. (See Example 10.8.)
$ type print print is a shell builtin $ type test test is a shell builtin $ type ls ls is a tracked alias for /usr/bin/ls $ type type type is an exported alias for whence -v $ type bc bc is /usr/bin/bc $ type if if is a keyword
The Exit Status. After a command or program terminates, it returns an exit status to the parent process. The exit status is a number between 0 and 255. By convention, when a program exits, if the status returned is zero, the command was successful in its execution. When the exit status is nonzero, the command failed in some way. The Korn shell status variable ? is set to the value of the exit status of the last command that was executed. Success or failure of a program is determined by the programmer who wrote the program. In shell scripts, you can explicitly control the exit status by using the exit command.
1 $ grep "ellie" /etc/passwd ellie:GgMyBsSJavd16s:9496:40:Ellie Quigley:/home/jody/ellie 2 $ echo $? 0 3 $ grep "nicky" /etc/passwd 4 $ echo $? 1 5 $ grep "scott" /etc/passsswd grep: /etc/passsswd: No such file or directory 6 $ echo $? 2
EXPLANATION
|
Multiple Commands and Command Grouping. A command line can consist of multiple commands. Each command is separated by a semicolon, and the command line is terminated with a newline.
$ ls; pwd; date
EXPLANATIONThe commands are executed from left to right until the newline is reached. Commands may also be grouped so that all of the output is either piped to another command or redirected to a file. |
$ ( ls ; pwd; date ) > outputfile
EXPLANATIONThe output of each of the commands is sent to the file called outputfile. |
Conditional Execution of Commands. With conditional execution, two command strings are separated by two special metacharacters, && and ||. The command on the right of either of these metacharacters will or will not be executed based on the exit condition of the command on the left.
$ cc prgm1.c o prgm1 && prgm1
EXPLANATIONIf the first command is successful (has a zero exit status), the command after the && is executed. |
$ cc prog.c >& err || mail bob < err
EXPLANATIONIf the first command fails (has a nonzero exit status), the command after the || is executed. |
Commands in the Background. Normally, when you execute a command, it runs in the foreground, and the prompt does not reappear until the command has completed execution. It is not always convenient to wait for the command to complete. By placing an ampersand (&) at the end of the command line, the shell will return the shell prompt immediately and execute the command in the background concurrently. You do not have to wait to start up another command. The output from a background job will be sent to the screen as it processes. Therefore, if you intend to run a command in the background, the output of that command should be redirected to a file or piped to another device such as a printer so that the output does not interfere with what you are doing.
1 $ man ksh | lp& 2 [1] 1557 3 $
EXPLANATION
|
The history mechanism keeps a numbered record of the commands that you have typed at the command line in a history file. You can recall a command from the history file and reexecute it without retyping the command. The history built-in command displays the history list. The default name for the history file is .sh_history, and it is located in your home directory.
The HISTSIZE variable, accessed when ksh first accesses the history file, specifies how many commands can be accessed from the history file. The default size is 128. The HISTFILE variable specifies the name of the command history file (~/.sh_history is the default) where commands are stored. The history file grows from one login session to the next; it becomes very large unless you clean it out. The history command is a preset alias for the fc l command.
The history Command/Redisplay Commands. The built-in history command lists previously typed commands preceded by a number. The command can take arguments to control the display.
1 $ history # Same as fc l 1 ls 2 vi file1 3 df 4 ps eaf 5 history 6 more /etc/passwd 7 cd 8 echo $USER 9 set 10 history 2 $ history n # Print without line numbers ls vi file1 df ps eaf history more /etc/passwd cd echo $USER set history history n 3 $ history 8 # List from 8th command to present 8 echo $USER 9 set 10 history 11 history n 12 history 8 4 $ history 3 # List this command and the 3 preceding it 10 history 11 history n 12 history 8 13 history 3 5 $ history 1 5 # List last 5 commands, preceding this one 13 history 3 # in reversed order. 12 history 8 11 history n 10 history 9 set 6 $ history 5 1 # Print last 5 commands, preceding this one 10 history # in order. 11 history -n 12 history 8 13 history -3 14 history 1 5 7 $ history # (Different history list) 78 date 79 ls 80 who 81 echo hi 82 history 8 $ history ls echo # Display from most recent ls command to 79 ls # most recent echo command. 80 who 81 echo hi 9 $ history r ls echo # r reverses the list 81 echo hi 80 who 79 ls
Reexecuting Commands with the r Command. The r command redoes the last command typed at the command line. If the r command is followed by a space and a number, the command at that number is reexecuted. If the r command is followed by a space and a letter, the last command that began with that letter is executed. Without any arguments, the r command reexecutes the most previous command on the history list.
1 $ r date date Mon Feb 15 12:27:35 PST 2001 2 $ r 3 redo command number 3 df Filesystem kbytes used avail capacity Mounted on /dev/sd0a 7735 6282 680 90% / /dev/sd0g 144613 131183 0 101% /usr /dev/sd2c 388998 211395 138704 60% /home. 3 $ r vi # Redo the last command that began with pattern vi. 4 $ r vi file1=file2 # Redo last command that began with vi # and substitute the first occurrence of # file1 with file2.
EXPLANATION
|
Command Line Editing. The Korn shell provides two built-in editors, emacs and vi, that allow you to interactively edit your history list. To enable the vi editor, add the set command listed below and put this line in your .profile file. The emacs built-in editor works on lines in the history file one line at a time, whereas the vi built-in editor works on commands consisting of more than one line. To set vi, type
set o vi or VISUAL=vi or EDITOR=/usr/bin/vi
If using emacs, type
set o emacs or VISUAL=emacs or EDITOR=/usr/bin/emacs
Note that set o vi overrides VISUAL, and VISUAL overrides EDITOR.
The vi Built-In Editor. To edit the history list, press the Esc key and use the standard keys that you would use in vi for moving up and down, left and right, deleting, inserting, and changing text. See Table 10.2. After making the edit, press the Enter key. The command will be executed and added to the bottom of the history list. To scroll upward in the history file, press the Esc key and then the K key.
Command | Function |
---|---|
Moving Through the History File | |
Esc k or + | Move up the history list. |
Esc j or - | Move down the history list. |
G | Move to first line in history file. |
5G | Move to fifth command in history file for string. |
/string | Search upward through history file. |
? | String search downward through history file. |
Moving Around on a Line | |
h | Move left on a line. |
l | Move right on a line. |
b | Move backward a word. |
e or w | Move forward a word. |
^ or 0 | Move to beginning of first character on the line. |
$ | Move to end of line. |
Editing with vi | |
a A | Append text. |
i I | Insert text. |
Editing with vi | |
dd dw x | Delete text into a buffer (line, word, or character). |
cc C | Change text. |
u U | Undo. |
yy Y | Yank (copy a line into buffer). |
p P | Put yanked or deleted line down below or above the line. |
r R | Replace a letter or any amount of text on a line. |
The emacs Built-In Editor. To start moving backward through the history file, press ^P. To move forward, press ^N . Use emacs editing commands to change or correct text, then press Enter and the command will be reexecuted. See Table 10.3.
Command | Function |
---|---|
Moving Through the History File | |
Ctrl-P | Move up history file. |
Ctrl-N | Move down history file. |
Ctrl-B | Move backward one character. |
Ctrl-R | Search backwards for string. |
Esc B | Move back one word. |
Ctrl-F | Move forward one character. |
Esc F | Move forward one word. |
Ctrl-A | Move to the beginning of the line. |
Ctrl-E | Move to the end of the line. |
Esc < | Move to the first line of the history file. |
Esc > | Move to the last line of the history file. |
Editing with emacs | |
Ctrl-U | Delete the line. |
Ctrl-Y | Put the line back. |
Ctrl-K | Delete from cursor to the end line. |
Ctrl-D | Delete a letter. |
Esc D | Delete one word forward. |
Esc H | Delete one word backward. |
Esc space | Set a mark at cursor position. |
Ctrl-X Ctrl-X | Exchange cursor and mark. |
Ctrl-P Ctrl-Y | Push region from cursor to mark into a buffer (Ctrl-P) and put it down (Ctrl-Y). |
FCEDIT[2] and Editing Commands. The fc command is a built-in command that can be used with the FCEDIT variable (typically set in the .profile file) to invoke the editor of your choice for editing the history file. This can be any editor on your system. The FCEDIT variable is set to the full pathname of your favorite editor. If FCEDIT is not set, the default editor, /bin/ed, is invoked when you type the fc command.
The FCEDIT variable should be set to the chosen editor. You can specify a number of items from the history list that you want to edit. After you edit the commands, the Korn shell will execute the whole file. Any commands that are preceded by a pound sign (#) will be treated as comments and will not be executed. See Table 10.4 for more on commenting and filename expansion.
EXPLANATION
|
Filename expansion is a mechanism that allows the user to type part of a filename and press the escape key to see the rest of the filename(s). In the examples, [Esc] represents the escape key.
Combination | Result |
---|---|
command [Esc]# | # precedes command with a #; puts it on the history list commented; command will not be executed. |
command [Esc]_ | Underscore inserts the last word of the last command at the cursor position. |
command [Esc] 2_ | Inserts the second word of the last command at the cursor position. |
word[Esc] * | *replaces the current word with all files matched. |
word[Esc] \ | \ replaces the current word with the first filename that starts with the same characters; filename expansion. |
word[Esc]= | Displays all filenames beginning with the same character as the current word and displays them in a numbered list. |
(Press the Esc Key for [Esc]. 1 $ ls a[Esc]= 1) abc 2) abc1 3) abc122 4) abc123 5) abc2 2 $ ls a[Esc]* ls abc abc1 abc122 abc123 abc2 abc abc1 abc122 abc123 abc2 3 $ print apples pears peaches apples pears peaches 4 $ print [Esc]_ print peaches peaches 5 $ print apples pears peaches plums apples pears peaches 6 $ print [Esc]2_ print pears pears
EXPLANATION
|
An alias is a Korn shell or user-defined abbreviation for a command. The alias name contains alphanumeric characters. Default aliases are provided by the shell and can be redefined or unset. Unlike the C shell aliases, the Korn shell does not support passing arguments. (If you need to use arguments, see "Functions".)
Aliases can be exported to subshells by storing them in the ENV file. (The commands in the ENV file are executed every time a new shell is spawned.) In the 1988 version of the Korn shell, the x option allows aliases to be exported to subshells as long as the new shell is not a separate invocation of ksh. Tracked aliases are provided by the Korn shell to speed up the time it takes the shell to search the path. Aliases can alias themselves; that is, they are recursive.
Listing Aliases. The alias built-in command lists all set aliases.
1 $ alias 2 autoload=typeset fu 3 false=let 0 4 functions=typeset f 5 hash=alias t 6 history=fc l 7 integer=typset i 8 r=fc e 9 stop=kill STOP 10 suspend=kill STOP $$ 11 true=: 12 type=whence v
EXPLANATION
|
Creating an Alias. The user can create aliases in the Korn shell. An alias is a nickname for an existing command or commands. The real command(s) is substituted for the alias when the shell evaluates the command line.
1 $ alias cl='clear' 2 $ alias l='ls laF' 3 $ alias ls='ls -aF' 4 $ \ls ..
EXPLANATION
|
Removing an Alias. The unalias command deletes an alias.
unalias cl
EXPLANATIONThe alias cl is removed from the list of set aliases. |
Tracked Aliases. To reduce the amount of time needed to do a search of the path, the Korn shell creates an alias when a command is first encountered and sets the alias equal to the full pathname of the command. This is called a tracked alias.[3]
The Korn shell has some preset tracked aliases that are defined when it is installed. To use tracked aliases, the set o trackall command is issued; it is normally set in the ENV file. To see all tracked aliases, type alias t.
$ alias t chmod=/bin/chmod ls=/bin/ls vi=/usr/ucb/vi who=/bin/who
EXPLANATIONThe t option to the built-in alias command displays those commands that have been aliased via the tracking mechanism. When the user types any of these commands, the shell will not search the path, but use the alias definition to invoke the command. |
Job control is used to control the execution of background and foreground jobs.
To use Korn shell job control, the monitor option (set o monitor) must be set on systems that do not support job control. See Table 10.5 for job control commands.
1 $ vi [1] + Stopped # vi 2 $ sleep 25& [2] 4538 3 $ jobs [2] + Running # sleep 25& [1] Stopped # vi 4 $ jobs l [2] + 4538 Running # sleep 25& [1] 4537 Stopped # vi 5 $ fg %1
EXPLANATION
|
Command | Meaning |
---|---|
jobs | Lists all unfinished processes in a numerically ordered list where the number of the job is enclosed in brackets. |
jobs l | Same as jobs, but includes the PID number of the job. |
^Z | Stops the current job. |
fg %n | Runs background job in foreground. |
bg %n | Runs job in background. |
wait %n | Waits for job number n to finish. |
kill %n | Kills job number n. |
Metacharacters are special characters used to represent something other than themselves. Table 10.6 lists some common Korn shell metacharacters and their functions.
Command | Function |
---|---|
\ | Literal interpretation of the following character. |
& | Background processing. |
; | Command separator. |
$ | Variable substitution. |
? | Match for a single character. |
[abc] | Match for one from a set of characters. |
[!abc] | Match for one not from the set of characters. |
* | Match for zero or more characters. |
(cmds ) | Execute commands in a subshell. |
{cmds} | Execute commands in current shell. |
1 $ ls -d * all files are displayed abc abc122 abc2 file1.bak file2.bak nonsense nothing one abc1 abc123 file1 file2 none noone 2 $ print hello \ # The carriage return is escaped > there hello there 3 $ rusers& # Process the rusers command in the background [1] 4334 $ 4 $ who; date; uptime # Commands are executed one at a time ellie console Feb 10 10:46 ellie ttyp0 Feb 15 12:41 ellie ttyp1 Feb 10 10:47 ellie ttyp2 Feb 5 10:53 Mon Feb 15 17:16:43 PST 2001 5:16pm up 5 days, 6:32, 1 user, load average: 0.28, 0.23, 0.01 5 $ print $HOME # The value of the HOME variable is printed /home/jody/ellie 6 $ print $LOGNAME # The value of the LOGNAME variable is printed ellie 7 $ ( pwd; cd / ; pwd ) /home/jody/ellie / $ pwd /home/jody/ellie 8 $ { pwd; cd /; pwd; } /home/jody/ellie / $ pwd / 9 $ ( date; pwd; ls ) > outfile $ cat outfile Mon Feb 15 15:56:34 PDT 2001 /home/jody/ellie foo1 foo2 foo3
EXPLANATION
|
When evaluating the command line, the shell uses metacharacters to abbreviate filenames or pathnames that match a certain set of characters, often called wildcards. The filename substitution metacharacters listed in Table 10.7 are expanded into an alphabetically listed set of filenames. The process of expanding a metacharacter into filenames is also called filename substitution, or globbing. If a metacharacter is used and there is no filename that matches it, the Korn shell treats the metacharacter as a literal character.
Metacharacter | Meaning |
---|---|
* | Matches zero or more characters. |
? | Matches exactly one character. |
[abc] | Matches one character in the set, a, b, or c. |
[a z] | Matches one character in the range: any character in the set between a and z. |
~ | Substitutes the user's home directory for ~. |
\ | Escapes or disables the metacharacter. |
The Asterisk. The asterisk is a wildcard that matches for zero or more of any character in a filename.
1 $ ls * abc abc1 abc122 abc123 abc2 file1 file1.bak file2 file2.bak none nonsense noone nothing nowhere one 2 $ ls *.bak file1.bak file2.bak 3 $ print a*c abc
EXPLANATION
|
The Question Mark. The question mark represents a single character in a filename. When a filename contains one or more question marks, the shell performs filename substitution by replacing the question mark with the character it matches in the filename.
1 $ ls abc abc1 abc122 abc123 abc2 file1 file1.bak file2 file2.bak none nonsense noone nothing nowhere one 2 $ ls a?c? abc1 abc2 3 $ ls ?? ?? not found 4 $ print abc??? abc122 abc123 5 $ print ?? ??
EXPLANATION
|
The Square Brackets. Brackets are used to match filenames containing one character from a set or range of characters.
1 $ ls abc abc1 abc122 abc123 abc2 file1 file1.bak file2 file2.bak none nonsense noone nothing nowhere one 2 $ ls abc[123] abc1 abc2 3 $ ls abc[1 3] abc1 abc2 4 $ ls [a z][a z][a z] abc one 5 $ ls [!f z]??? abc1 abc2 6 $ ls abc12[2-3] abc122 abc123
EXPLANATION
|
Escaping the Metacharacters. To use a metacharacter as a literal character, use the backslash to prevent the metacharacter from being interpreted.
1 $ ls abc file1 youx 2 $ print How are you? How are youx 3 $ print How are you\? How are you? 4 $ print When does this line \ > ever end\? When does this line ever end?
EXPLANATION
|
Tilde and Hyphen Expansion. The tilde character was adopted by the Korn shell (from the C shell ) for pathname expansion. The tilde by itself evaluates to the full pathname of the user's home directory. When the tilde is appended with a username, it expands to the full pathname of that user
The hyphen character refers to the previous working directory; OLDPWD also refers to the previous working directory.
1 $ echo ~ /home/jody/ellie 2 $ echo ~joe /home/joe 3 $ echo ~+ /home/jody/ellie/perl 4 $ echo ~ /home/jody/ellie/prac 5 $ echo $OLDPWD /home/jody/ellie/prac 6 $ cd /home/jody/ellie/prac
EXPLANATION
|
New ksh Metacharacters. The new Korn shell metacharacters are used for filename expansion in a way that is similar to the regular expression metacharacters of egrep and awk. The metacharacter preceding the characters enclosed in parentheses controls what the pattern matches. See Table 10.8.
1 $ ls abc abc1 abc122 abc123 abc2 file1 file1.bak file2 file2.bak none nonsense noone nothing nowhere one 2 $ ls abc?(1|2) abc abc1 abc2 3 $ ls abc*([1 5]) abc abc1 abc122 abc123 abc2 4 $ ls abc+([1 5]) abc1 abc122 abc123 abc2 5 $ ls no@(thing|ne) none nothing 6 $ ls no!(one|nsense) none nothing nowhere
EXPLANATION
|
Regular Expression | Meaning |
---|---|
abc?(2|9)1 | ? matches zero or one occurrences of any pattern in the parentheses. The vertical bar represents an or condition; e.g., either 2 or 9. Matches abc21, abc91, or abc1. |
abc*([0 9]) | * matches zero or more occurrences of any pattern in the parentheses. Matches abc followed by zero or more digits; e.g., abc, abc1234, abc3, abc2, etc. |
abc+([0 9]) | + matches one or more occurrences of any pattern in the parentheses. Matches abc followed by one or more digits; e.g., abc3, abc123, etc. |
no@(one|ne) | @ matches exactly one occurrence of any pattern in the parentheses. Matches noone or none. |
no!(thing|where) | ! matches all strings except those matched by any of the pattern in the parentheses. Matches no, nobody, or noone, but not nothing or nowhere. |
The noglob Variable. If the noglob variable is set, filename substitution is turned off, meaning that all metacharacters represent themselves; they are not used as wildcards. This can be useful when searching for patterns containing metacharacters in programs like grep, sed, or awk. If noglob is not set, all metacharacters must be escaped with a backslash if they are not to be interpreted.
1 % set -o noglob # or set -f 2 % print * ?? [] ~ $LOGNAME * ?? [] /home/jody/ellie ellie 3 % set +o noglob # or set +f
EXPLANATION
|
Local Variables. Local variables are given values that are known only to the shell in which they are created. Variable names must begin with an alphabetic or underscore character. The remaining characters can be alphabetic, decimal digits zero to nine, or an underscore character. Any other characters mark the termination of the variable name.
Setting and Referencing Local Variables. When assigning a value to a variable, there can be no whitespace surrounding the equal sign. To set the variable to null, the equal sign is followed by nothing. If more than one word is assigned to a variable, it must be quoted to protect the whitespace; otherwise, the shell prints an error message and the variable is undefined.
If a dollar sign is prepended to the variable name, the value assigned to that variable can be referenced. If other characters are attached to a variable name, curly braces are used to shield the name of the variable from the extra characters.
1 $ state=Cal $ echo $state Cal 2 $ name="Peter Piper" $ echo $name Peter Piper 3 $ x= $ echo $x # Blank line appears when a variable is either unset or set to null $ 4 $ state=Cal $ print ${state}ifornia California
EXPLANATION
|
The Scope of Local Variables. A local variable is known only to the shell in which it was created. It is not passed on to subshells. The $$ variable is a special variable containing the PID (process identification number) of the current shell.
1 $ echo $$ 1313 2 $ round=world $ echo $round world 3 $ ksh # Start a subshell 4 $ echo $$ 1326 5 $ echo $round 6 $ exit # Exits this shell, returns to parent shell 7 $ echo $$ 1313 8 $ echo $round world
EXPLANATION
|
Setting Read-Only Variables. A read-only variable cannot be redefined or unset. It can be set with the readonly or typeset r built-in commands. You may want to set variables to readonly for security reasons when running in privileged mode.
1 $ readonly name=Tom $ print $name Tom 2 $ unset name ksh: name: is read only 3 $ name=Joe ksh name: is read only 4 $ typeset -r PATH $ PATH=${PATH}:/usr/local/bin ksh: PATH: is read only
EXPLANATION
|
Environment Variables. Environment variables are available to the shell in which they are created and any subshells or processes spawned from that shell. By convention, environment variables are capitalized.
The shell in which a variable is created is called the parent shell. If a new shell is started from the parent shell, it is called the child shell. Some of the environment variables, such as HOME, LOGNAME, PATH, and SHELL, are set before you log in by the /bin/login program. Normally, environment variables are set in the .profile file in the user's home directory.
Setting Environment Variables. To set environment variables, the export command is used either after assigning a value or when the variable is set. All variables in a script can be exported by turning on the allexport option to the set command.
1 $ TERM=wyse ; export TERM 2 $ export NAME ="John Smith" $ print $NAME John Smith 3 $ print $$ 319 4 $ ksh 5 $ print $$ 340 6 $ print $NAME John Smith 7 $ NAME="April Jenner" $ print $NAME April Jenner 8 $ exit 9 $ print $$ 319 10 $ print $NAME John Smith
EXPLANATION
|
Special Environment Variables. The Korn shell assigns default values to the environment variables, PATH, PS1, PS2, PS3, PS4, MAILCHECK, FCEDIT, TMOUT, and IFS. The SHELL, LOGNAME, USER, and HOME are set by the /bin/login program. You can change the values of the defaults and set the others listed in Table 10.9.
Variable Name | Meaning |
---|---|
_ (underscore) | The last argument of the previous command. |
CDPATH | The search path for the cd command. A colon-separated list of directories used to find a directory if the / , ./, or ../ is not at the beginning of the pathname. |
COLUMNS | If set, defines the width of the edit window for shell edit modes and the select command. |
EDITOR | Pathname for a built-in editor: emacs, gmacs, or vi. |
ENV | A variable set to the name of a file, containing functions and aliases, that the Korn shell will invoke when the ksh program is invoked. On versions newer than 1988, this file is only executed when ksh is invoked interactively, not for noninteractive shells. The variable is not expanded if the privileged option is turned on. |
ERRNO | System error number. Its value is the error number of the most recently failed system call. |
FCEDIT | Default editor name for the fc command. On versions newer than 1988, this variable is called HISTEDIT, and the fc command is hist. |
FPATH | A colon-separated list of directories that defines the search path for directories containing auto-loaded functions. |
HISTEDIT | For versions of the Korn shell newer than 1988, the new name for FCEDIT. |
HISTFILE | Specifies file in which to store command history. |
HISTSIZE | Maximum number of commands from the history that can be accessed; default is 128. |
HOME | Home directory; used by cd when no directory is specified. |
IFS | Internal field separators, normally SPACE, TAB, and NEWLINE, used for field splitting of words resulting from command substitution, lists in loop constructs, and reading input. |
LINENO | Current line number in script. |
LINES | Used in select loops for vertically displaying menu items; default is 24. |
If this parameter is set to the name of a mail file and the MAILPATH parameter is not set, the shell informs the user of the arrival of mail in the specified file. | |
MAILCHECK | This parameter specifies how often (in seconds) the shell will check for the arrival of mail in the files specified by the MAILPATH or MAIL parameters. The default value is 600 seconds (10 minutes). If set to zero, the shell will check before issuing each primary prompt. |
MAILPATH | A colon-separated list of filenames. If this parameter is set, the shell informs the user of the arrival of mail in any of the specified files. Each filename can be followed by a % and a message that will be printed when the modification time changes. The default message is You have mail. |
OLDPWD | Last working directory. |
PATH | The search path for commands; a colon-separated list of directories the shell uses to search for the command you want to execute. |
PWD | Present working directory; set by cd. |
PPID | Process ID of the parent process. |
PS1 | Primary prompt string, by default $. |
PS2 | Secondary prompt string, by default >. |
PS3 | Selection prompt string used with the select command, by default #?. |
PS4 | Debug prompt string used when tracing is turned on, by default +. |
RANDOM | Random number generated each time the variable is referenced. |
REPLY | Set when read is not supplied arguments. |
SHELL | When the shell is invoked, it scans the environment for this name. The shell gives default values to PATH, PS1, PS2, MAILCHECK, and IFS. HOME and MAIL are set by login. |
TMOUT | Specifies number of seconds to wait for input before exiting. |
VISUAL | Specifies editor for in-line command editing: emacs, gmacs, or vi. |
Listing Set Variables. There are three built-in commands that print the value of variables: set, env, and typeset. The set command prints all variables, local and global. The env command prints only global variables. The typeset command prints all variables, integers, functions, and exported variables. The set -o command prints all options set for the Korn shell.
1 $ env # Partial list LOGNAME=ellie TERMCAP=sun cmd:te=\E[>4h:ti=\E[>4l:tc=sun: USER=ellie DISPLAY=:0.0 SHELL=/bin/ksh HOME=/home/jody/ellie TERM=sun cmd LD_LIBRARY_PATH=/usr/local/OW3/lib PWD=/home/jody/ellie/perl 2 $ typeset export MANPATH export PATH integer ERRNO export FONTPATH integer OPTIND function LINENO export OPENWINHOME export LOGNAME function SECONDS integer PPID PS3 PS2 export TERMCAP OPTARG export USER export DISPLAY function RANDOM export SHELL integer TMOUT integer MAILCHECK 3 $ set DISPLAY=:0.0 ERRNO=10 FCEDIT=/bin/ed FMHOME=/usr/local/Frame 2.1X FONTPATH=/usr/local/OW3/lib/fonts HELPPATH=/usr/local/OW3/lib/locale:/usr/local/OW3/lib/help HOME=/home/jody/ellie IFS= LD_LIBRARY_PATH=/usr/local/OW3/lib LINENO=1 LOGNAME=ellie MAILCHECK=600 MANPATH=/usr/local/OW3/share/man:/usr/local/OW3/man:/ usr/local/man:/usr/local/doctools/man:/usr/man OPTIND=1 PATH=/home/jody/ellie:/usr/local/OW3/bin:/usr/ucb:/ usr/local/doctools/bin:/usr/bin:/usr/local:/usr/etc:/etc:/ usr/spool/news/bin:/home/jody/ellie/bin:/usr/lo PID=1332 PS1=$ PS2=> PS3=#? PS4=+ PWD=/home/jody/ellie/kshprog/joke RANDOM=4251 SECONDS=36 SHELL=/bin/ksh TERM=sun cmd TERMCAP=sun cmd:te=\E[>4h:ti=\E[>4l:tc=sun: TMOUT=0 USER=ellie _=pwd name=Joe place=San Francisco x= 4 set -o allexport off bgnice on emacs off errexit off gmacs off ignoreeof off interactive on keyword off markdirs off monitor on noexec off noclobber off noglob off nolog off nounset off privileged off restricted off trackall off verbose off viraw off xtrace off
EXPLANATION
|
Unsetting Variables. Both local and environment variables can be unset by using the unset command (unless the variables are set to readonly).
unset name; unset TERM
EXPLANATIONThe variables name and Term are no longer defined for this shell. |
Printing the Values of Variables. The echo command (used in Bourne and C shells) is still effective in this shell, but the print command has more options and is more efficient. Both the echo command and print command are built-in to the shell. The print command has a number of options to control its output. They are listed in Table 10.10.
Option | Meaning |
---|---|
r | Prevents escape sequences. |
R | Prevents ksh from treating a 2 or x as a print argument; turns off the dash if preceding an argument (except n); \t, \c, \c are not recognized as special and appear unchanged when printed without the \. |
un | Redirects output to file descriptor n. |
n | No newline in output; like echo n. |
p | Sends output to a coprocess or pipe (&|) rather than to standard output. |
s | Output is appended to the history file as a command rather than to standard output. |
Any arguments that follow are not print options. The dash allows arguments that contain a hyphen, e.g., 2. | |
f | For versions newer than 1988, used to emulate printf. |
1 $ print Hello my friend and neighbor! Hello my friend and neighbor! 2 $ print "Hello friends" Hello friends 3 $ print r "\n" \n 4 $ print -s "date +%H" $ history -2 132 print -s "date +%H" 133 date +%H 134 history -2 $ r 133 09 5 $ print n $HOME /home/jody/ellie 6 $ var=world $ print ${var}wide worldwide 7 $ print x is an option ksh: print: bad option(s) 8 $ print x is an option x is an option
EXPLANATION
|
Escape Sequences. Escape sequences consist of a character preceded by a backslash and have a special meaning when enclosed within quotes. (See Table 10.11.)
The print command, without the -r and -R options, formats output when any of the following escape sequences are placed within a string. The string must be enclosed in double or single quotes.
1 $ print '\t\t\tHello\n' Hello $ 2 $ print "\aTea \tTime!\n\n" Ding ( bell rings ) Tea Time!
EXPLANATION
|
Backslash Character | Meaning |
---|---|
\a | Bell character. |
\b | Backspace. |
\c | Suppress newline and ignore any arguments that follow \c. |
\f | Formfeed. |
\n | Newline. |
\r | Return. |
\t | Tab. |
\v | Vertical tab. |
\\ | Backslash. |
\0x | Eight-bit character with a 1-, 2-, or 3-digit ASCII value, as in print \0124. |
\E | Only on versions newer than 1988; used for an escape sequence. |
Variable Expressions and Expansion Modifiers. Variable expressions can be tested and modified by using special modifiers. The modifier provides a shortcut conditional test to check whether a variable has been set, and then, depending on the modifier, may assign a default value to the variable. These expressions can be used with conditional constructs such as if and elif. See Table 10.12.
The colon does not have to be used with the modifier. Using the colon with the modifier checks whether the variable is not set or is null; without the colon, a variable set to null is considered a set variable.
Expression | Function |
---|---|
${variable: word} | If variable is set and is nonnull, substitute its value; otherwise, substitute word. |
${variable:=word} | If variable is not set or is null, set it to word; the value of variable is substituted permanently. Positional parameters may not be assigned in this way. |
${variable:+word} | If variable is set and is nonnull, substitute word; otherwise substitute nothing. |
${variable:?word} | If variable is set and is nonnull, substitute its value; otherwise, print word and exit from the shell. If word is omitted, the message parameter null or not set is printed. |
(Using Temporary Default Values) 1 $ fruit=peach 2 $ print ${fruit: plum} peach 3 $ print ${newfruit: apple} apple 4 $ print $newfruit 5 $ print ${TERM:-vt120} sun-cmd
EXPLANATION
|
(Assigning Permanent Default Values) 1 $ name= 2 $ print ${name:=Patty} Patty 3 $ print $name Patty 4 $ print ${TERM:=vt120} vt120 $ print $TERM vt120
EXPLANATION
|
(Assigning Temporary Alternate Value) 1 $ foo=grapes 2 $ print ${foo:+pears} pears $ print $foo grapes
EXPLANATION
|
(Creating Error Messages Based on Default Values) 1 $ print ${namex:?"namex is undefined"} ksh: namex: namex is undefined 2 $ print ${y?} ksh: y: parameter null or not set
EXPLANATION
|
(Line from a System Script) if [ "${uid:=0}" -ne 0 ]
EXPLANATIONIf the UID (user ID) has a value, it will not be changed; if it does not have a value, it will be assigned the value zero (superuser). The value of the variable will be tested for nonzero. This line was taken from the /etc/shutdown program (SVR4/Solaris 2.5). It is here to give you an example of how variable modifiers are used. |
Variable Expansion of Substrings. Pattern matching arguments are used to strip off certain portions of a string from either the front or end of the string. The most common use for these operators is stripping off pathname elements from the head or tail of the path. See Table 10.13.
Expression | Function |
---|---|
${variable%pattern} | Matches the smallest trailing portion of the value of variable to pattern and removes it. |
${variable%%pattern} | Matches the largest trailing portion of the value of variable to pattern and removes it. |
${variable#pattern} | Matches the smallest leading portion of the value of variable to pattern and removes it. |
${variable##pattern} | Matches the largest leading portion of the value of variable to pattern and removes it. |
1 $ pathname="/usr/bin/local/bin" 2 $ print ${pathname%/bin*} /usr/bin/local
EXPLANATION
|
1 $ pathname="usr/bin/local/bin" 2 $ print ${pathname%%/bin*} /usr
EXPLANATION
|
1 $ pathname=/home/lilliput/jake/.cshrc 2 $ print ${pathname#/home} /lilliput/jake/.cshrc
EXPLANATION
|
1 $ pathname=/home/liliput/jake/.cshrc 2 $ print ${pathname##*/} .cshrc
EXPLANATION
|
Variable Attributes: The typeset Command. The attributes of a variable, such as its case, width, and left or right justification, can be controlled by the typeset command. When the typeset command changes the attributes of a variable, the change is permanent. The typeset function has a number of other functions. See Table 10.14.
1 $ typeset u name="john doe" $ print "$name" JOHN DOE # Changes all characters to uppercase. 2 $ typeset l name $ print $name john doe # Changes all characters to lowercase. 3 $ typeset L4 name $ print $name john # Left-justified fixed-width 4-character field. 4 $ typeset R2 name $ print $name # Right-justified fixed-width 2-character field. hn 5 $ name="John Doe" $ typeset Z15 name # Null padded sting, 15-space field. width $ print "$name" John Doe 6 $ typeset LZ15 name # Left-justified, 15-space field width. $ print "$name$name" John Doe John Doe 7 $ integer n=25 $ typeset -Z15 n # Left-justified, zero-padded integer. $ print "$n" 000000000000025 8 $ typeset lL1 answer=Yes # Left justify one lowercase letter. $ print $answer y
EXPLANATION
|
Command | What It Does |
---|---|
typeset | Displays all variables. |
typeset i num | Will only accept integer values for num. |
typeset x | Displays exported variables. |
typeset a b c | If defined in a function, creates a, b, and c to be local variables. |
typeset r x=foo | Sets x to foo and then makes it read-only. |
Positional Parameters. Normally, the special built-in variables, often called positional parameters, are used in shell scripts when passing arguments from the command line, or used in functions to hold the value of arguments passed to the function. The variables are called positional parameters because they are referenced by numbers 1, 2, 3, and so on, representing their respective positions in the parameter list. See Table 10.15.
The name of the shell script is stored in the $0 variable. The positional parameters can be set and reset with the set command.
Expression | Function |
---|---|
$0 | References the name of the current shell script. |
$1 $9 | Positional parameters 1 9. |
${10} | Positional parameter 10. |
$# | Evaluates to the number of positional parameters. |
$* | Evaluates to all the positional parameters. |
$@ | Same as $*, except when double quoted. |
"$*" | Evaluates to "$1 $2 $3", etc. |
"$@" | Evaluates to "$1" "$2" "$3", etc. |
1 $ set tim bill ann fred $ print $* # Prints all the positional parameters. tim bill ann fred 2 $ print $1 # Prints the first position. tim 3 $ print $2 $3 # Prints the second and third position. bill ann 4 $ print $# # Prints the total number of positional 4 # parameters. 5 $ set a b c d e f g h i j k l m $ print $10 # Prints the first positional parameter a0 # followed by a 0. $ print ${10} ${11} # Prints the 10th and 11th positions. j k 6 $ print $# 13 7 $ print $* a b c d e f g h i j k l m 8 $ set file1 file2 file3 $ print \$$# $3 9 $ eval print \$$# file3
EXPLANATION
|
The Korn shell has some special built-in variables, as shown in Table 10.16.
Variable | Meaning |
---|---|
$$ | PID of the shell. |
$ | ksh options currently set. |
$? | Exit value of last executed command. |
$! | PID of last job put in background. |
1 $ print The pid of this shell is $$ The pid of this shell is 4725 2 $ print The options for this korn shell are $ The options for this korn shell are ismh 3 $ grep dodo /etc/passwd $ print $? 1 4 $ sleep 25& [1] 400 $ print $! 400
EXPLANATION
|
Quotes are used to protect special metacharacters from interpretation. They can cause major debugging hassles in all shell scripts. Single quotes must be matched. They protect special metacharacters from being interpreted by the shell. Double quotes also must be matched. They protect most characters from interpretation by the shell, but allow variable and command substitution characters to be processed. Single quotes will protect double quotes, and double quotes will protect single quotes. The Korn shell, unlike the Bourne shell, will inform you if you have mismatched quotes by sending an error message to standard error with the line where it detects that the quotes were mismatched.
The Backslash. The backslash is used to protect (or escape) a single character from interpretation.
1 $ print Where are you going\? Where are you going? 2 $ print Start on this line and \ > go to the next line. Start on this line and go to the next line.
EXPLANATION
|
Single Quotes. Single quotes must be matched. They protect all metacharacters from interpretation. To print a single quote, it must be enclosed in double quotes or escaped with a backslash.
$ print 'hi there > how are you? > When will this end? > When the quote is matched > oh' hi there how are you? When will this end? When the quote is matched oh 2 $ print 'Do you need $5.00?' Do you need $5.00? 3 $ print 'Mother yelled, "Time to eat!"' Mother yelled, "Time to eat!"
EXPLANATION
|
Double Quotes. Double quotes must be matched, will allow variable and command substitution, and protect any other special metacharacters from being interpreted by the shell.[4]
1 $ name=Jody 2 $ print "Hi $name, I'm glad to meet you!" Hi Jody, I'm glad to meet you! 3 $ print "Hey $name, the time is 'date'" Hey Jody, the time is Fri Dec 18 14:04:11 PST 2001
EXPLANATION
|
Command substitution is used when assigning the output of a command to a variable, or when substituting the output of a command into a string. The Bourne and C shells use backquotes to perform command substitution. The Korn shell does allow the backquote format (calling it "obsolescent"), but placing the command in parentheses is the preferred method because it has simpler quoting rules and makes nesting commands easier.
FORMAT'Unix command' # Old method with backquotes $(Unix command) # New method |
(Old Way) 1 $ print "The hour is 'date +%H'" The hour is 09 2 $ name='nawk F: ''{print $1}' database' $ print $name Ebenezer Scrooge 3 $ ls 'ls /etc' shutdown 4 $ set 'date' 5 $ print $* Sat Oct 13 09:35:21 PDT 2001 6 $ print $2 $6 Oct 2001
EXPLANATION
|
The ksh alternate for using backquotes in command substitution is presented in Example 10.56.
(The New ksh Way) 1 $ d=$(date) print $d Sat Oct 20 09:35:21 PDT 2001 2 $ line = $(< filex) 3 $ print The time is $(date +%H) The time is 09 4 $ machine=$(uname n) $ print $machine jody 5 $ dirname="$(basename $(pwd)) " # Nesting commands $ print $dirname bin
EXPLANATION
|
This section introduces functions so that you can use them interactively or store them in your initialization files. Later, when discussing scripts, functions will be covered in more depth. Functions can be used when an alias is not enough, that is, for passing arguments. Functions are often defined in the user's initialization file, .profile. They are like mini-scripts, but unlike scripts, functions run in the current environment; that is, the shell does not fork a child process to execute a function. All variables are shared with the shell that invoked the function. Often functions are used to improve the modularity of a script. Once defined, they can be used repeatedly and even stored in another directory.
Functions must be defined before they are invoked; there are two formats used to define them. One format came from the Bourne shell and the other is new with the Korn shell. Functions can be exported from one invocation of the shell to the next. The typeset function and unset command can be used to list and unset functions. See Table 10.17.
Command | Function |
---|---|
typeset f | Lists functions and their definitions; functions is an alias for typeset f. |
typeset +f | Lists only function names. |
unset f name | Unset a function. |
Defining Functions. There are two acceptable formats for defining functions: the Bourne shell format (still allowed for upward compatibility) and the new Korn shell format. A function must be defined before it can be used.
FORMAT(Bourne Shell) functionname() { commands ; commands; }[5] (Korn Shell) function functionname { commands; commands; } |
1 $ function fun { pwd; ls; date; } 2 $ fun /home/jody/ellie/prac abc abc123 file1.bak none nothing tmp abc1 abc2 file2 nonsense nowhere touch abc122 file1 file2.bak noone one Tue Feb 9 11:15:48 PST 2001 3 $ function greet { print "Hi $1 and $2"; } 4 greet tom joe # Here $1 is tom and $2 is joe Hi tom and joe 5 $ set jane nina lizzy 6 $ print $* jane nina lizzy 7 $ greet tom joe Hi tom and joe 8 $ print $1 $2 jane nina
EXPLANATION
|
Functions and Aliases. When processing the command line, the shell looks for aliases before special built-in commands and for special built-ins before functions. If a function has the same name as a built-in, the built-in will take priority over the function. An alias for a special built-in can be defined, and then the function name can be given the name of the alias to override the order of processing.
(The ENV File) 1 alias cd=_cd 2 function _cd { 3 \cd $1 4 print $(basename $PWD) 5 } (The Command Line) $ cd / / $ cd $HOME/bin bin $ cd .. ellie
EXPLANATION
|
Listing Functions. To list functions and their definitions, use the typeset command.
(The Command Line) 1 $ typeset f function fun { pwd; ls; date; } function greet { print "hi $1 and $2"; } 2 $ typeset +f fun greet
EXPLANATION
|
Unsetting Functions. When a function is unset, it will be removed from the shell's memory.
(The Command Line) 1 $ typeset f function fun { pwd; ls; date; } function greet { print "hi $1 and $2"; } 2 $ unset -f fun 3 $ typeset f function greet { print "hi $1 and $2"; }
EXPLANATION
|
The shell opens three files (called streams) whenever a program is started: stdin, stdout, and stderr. Standard input normally comes from the keyboard and is associated with file descriptor 0. Standard output normally goes to the screen, file descriptor 1. Standard error normally goes to the screen, file descriptor 2. Standard input, output, and error can be redirected to or from a file. See Table 10.18 for a list of redirection operators.
Operator | Function |
---|---|
< | Redirect input. |
> | Redirect output. |
>> | Append output. |
2> | Redirect error. |
1>&2 | Redirect output to where error is going. |
2>&1 | Redirect error to where output is going. |
(The Command Line) 1 $ tr '[A-Z]' '[a-z]' < myfile # Redirect input 2 $ ls > lsfile # Redirect output $ cat lsfile dir1 dir2 file1 file2 file3 3 $ date >> lsfile # Redirect and append output $ cat lsfile dir1 dir2 file1 file2 file3 Mon Sept 17 12:57:22 PDT 2001 4 $ cc prog.c 2> errfile # Redirect error 5 $ find . name \*.c print > founditfile 2> /dev/null 6 $ find . name \*.c print > foundit 2>&1 7 $ print "File needs an argument" 1>&2 8 $ function usage { print "Usage: $0 [-y] [-g] filename" 1>&2 ; exit 1; }
EXPLANATION
|
The exec Command and Redirection. The exec command can be used to replace the current program with the one being execed. Another use for the exec command is to change standard output or input without creating a subshell. If a file is opened with exec, subsequent read commands will move the file pointer down the file a line at a time until end of file. The file must be closed to start reading from the beginning again. However, if using UNIX utilities such as cat and sort, the operating system closes the file after each command has completed. See Table 10.19 for exec functionality.
Command | Function |
---|---|
exec ls | ls will execute in place of the shell. When ls is finished, the shell in which it was started does not return. |
exec < filea | Open filea for reading standard input. |
exec > filex | Open filex for writing standard output. |
exec 2> errors | Open errors for writing standard error. |
exec 2> /dev/console | Sends all error messages to the console. |
exec 3< datfile | Open datfile as file descriptor 3 for reading input. |
sort <&3 | datfile is sorted. |
exec 4>newfile | Open newfile as file descriptor 4 for writing. |
ls >&4 | Output of ls is redirected to newfile. |
exec 5<&4 | Make fd 5 a copy of fd 4. Both descriptors refer to newfile. |
exec 3<& | Close file descriptor 3, datfile. |
When the output of a command is redirected from the screen to a file, the Korn shell creates a child (fork) shell to rearrange the file descriptors, as shown in Figure 10.2.
A pipe takes the output from the command on the left-hand side of the pipe symbol and sends it to the input of a command on the right-hand side of the pipe symbol. A pipeline can consist of more than one pipe.
1 $ who > tmp 2 $ wc l tmp 4 tmp 3 $ rm tmp 4 $ who | wc -l # Using the pipe
EXPLANATIONThe purpose of lines 1 through 3 is to count the number of people logged on (who), save the output of the command in a file (tmp), use the wc l to count the number of lines in the tmp file (wc l), and then remove the tmp file; that is, find the number of people logged on. The pipe performs the same task in one command.
|
1 $ ls | more < lists (ls) all files one page at a time (more) > 2 $ du ~ | sort n | sed n '$p' 72388 /home/jody/ellie 3 $ cat | lp or cat | lpr
EXPLANATION
|
A here document captures in-line input for programs such as mail, sort, and cat. Input is placed between two words or symbols. The first word is preceded by a UNIX command and the << symbol. The next line(s) consist of the input to be received by the command. The last line consists of a second word that exactly matches the first word. This word is called the final terminator and marks the end of input. It is used in the same way Control-D is used to terminate input. There can be no spaces surrounding the final terminator. If the first word is preceded by the << , leading tabs (and only tabs) may precede the final terminator. Normally, here documents are used in shell scripts, rather than interactively. A good use for a here document is to create a menu in a script.
FORMATUNIX command << TERMINATOR lines of input input TERMINATOR |
(The Command Line) 1 $ cat << FINISH# FINISH is a user-defined terminator 2 > Hello there $LOGNAME 3 > The time is $(date) > I can't wait to see you!!! 4 > FINISH 5 Hello there ellie The time is Sun Feb 7 19:42:16 PST 2001 I can't wait to see you!! 6 $
EXPLANATION
|
(From the .profile File) 1 print "Select a terminal type" 2 cat << EOF [1] sun [2] ansi [3] wyse50 3 EOF 4 read TERM ...
EXPLANATION
|
(The Command Line) 1 $ cat << DONE >Hello there >What's up? >Bye now The time is $(date). 2 > DONE 3 Hello there What's up? Bye now The time is Sun Feb 7 19:48:23 PST 2001.
EXPLANATION
|
The time Command. The time command is a ksh built-in command. The time command prints the following to standard error: elapsed time, the user time, and the system time used to execute a command.
1 $ time sleep 3 real 0m3.15s took 3.15 seconds to run user 0m0.01s sleep used its own code for .01 seconds sys 0m0.08s and kernel code for .08 seconds 2 $ time ps ef | wc l # time is measured for all commands in 38 # the pipeline real 0m1.03s user 0m0.01s sys 0m0.10s
EXPLANATION
|
The TMOUT variable is an integer type. It can be set to force users to type commands within a certain period of time. TMOUT, by default, is set to zero, allowing the user an infinite amount of time to type commands after the PS1 prompt. If TMOUT is set to a value greater than zero, the shell will terminate after the time has expired. Sixty additional seconds will be allotted as the grace period before actually exiting the shell.
$ TMOUT=600 time out in 60 seconds due to inactivity ksh: timed out waiting for input
EXPLANATIONThe TMOUT variable is set to 600 seconds. If the user does nothing for 600 seconds, a message will appear on the screen and then an additional 60 seconds grace period will be allotted before the shell exits. If you do this at the prompt, your current shell exits. |
Writing shell scripts requires a few steps, as outlined in the following section.
A shell script is normally written in an editor and consists of commands interspersed with comments. Comments are preceded by a pound sign.
The First Line. At the top-left corner, to indicate the program that will be executing the lines in the script, #!/bin/ksh is commonly used. The #! is called a magic number and is used by the kernel to identify the program that should be interpreting the lines in the script. This line must be the top line of your script. The Korn shell also provides a number of invocation options that control how the shell behaves. These options are listed at the end of this chapter.
Comments. Comments are lines preceded by a pound sign. They are used to document your script. It is sometimes difficult to understand what the script is supposed to do if it is not commented. Although comments are important, they are often too sparse or not even used at all. Try to get used to commenting what you are doing, not only for someone else, but also for yourself.
Executable Statements and Korn Shell Constructs. A Korn shell program consists of a combination of UNIX commands, Korn shell commands, programming constructs, and comments.
Naming and Storing Scripts. When naming scripts, it is a good idea to give the script a meaningful name and one that does not conflict with other UNIX commands or aliases. For example, you may want to call the script test because it is merely performing some simple test procedure, but test is a built-in command and you may find you are executing the wrong test. Additionally, if you name the file foo, goo, boobar, and so forth, in a few days or even hours you may not have any idea what is in that script!
After you have tested your script and found it "bug-free," make a directory where you can store the scripts, then set the path so that your scripts can be executed from anywhere in the directory hierarchy.
1 $ mkdir ~/bin 2 $ mv myscript ~/bin (In .profile) 3 export PATH=${PATH}:~/bin 4 $ . .profile
EXPLANATION
|
Making a Script Executable. When you create a file, it is not automatically given execute permission (regardless of how umask is set). You need this permission to run your script. Use the chmod command to turn on execute permission.
1 $ chmod +x myscript 2 $ ls -lF myscript -rwxr--xr--x 1 ellie 0 Jul 12 13:00 joker*
EXPLANATION
|
Using a Script as an Argument to ksh. If you don't make a script executable, you can execute it by passing it as an argument to the ksh command:
(The Command Line) $ ksh myscript
EXPLANATIONIf the ksh program is given a scriptname as its argument, it will execute the script and the #! line is not necessary or even used. |
A Scripting Session. In Example 10.72, the user will create a script in the editor. After saving the file, the execute permissions are turned on, and the script is executed. If there are errors in the program, the Korn shell will respond immediately.
(The Script) 1 #!/bin/ksh 2 # This is the first Korn shell program of the day. # Scriptname: greetings # Written by: Karen Korny 3 print "Hello $LOGNAME, it's nice talking to you." 4 print "Your present working directory is $(pwd)." print "You are working on a machine called $(uname -n)." print "Here is a list of your files." 5 ls # List files in the present working directory print "Bye for now $LOGNAME. The time is $(date +%T)!" (The Command Line) $ chmod +x greetings $ greetings 3 Hello karen, it's nice talking to you. 4 Your present working directory is /home/lion/karen/junk Your are working on a machine called lion. Here is a list of your files. 5 Afile cplus letter prac Answerbook cprog library prac1 bourne joke notes perl5 Bye for now karen. The time is 18:05:07!
EXPLANATION
|
The read command is used to take input from the terminal or from a file until the newline is reached. The Korn shell provides some additional options for the read command. See Table 10.20 for different read formats. See Table 10.21 for read options.
Format | Meaning |
---|---|
read answer | Reads a line from standard input and assigns it to the variable answer. |
read first last | Reads a line from standard input to the first whitespace or newline, putting the first word typed into the variable first and the rest of the line into the variable last. |
read response?"Do you feel okay?" | Displays the string Do you feel okay? to standard error and waits for user to type a reply, then puts the reply in the variable response. This form of read requires and accepts only one variable. Whatever the user types, until the newline, will be stored in response. |
read u3 line | Reads a line from file descriptor 3 into variable line. |
read | Reads input into a built-in variable, REPLY. |
Options | Meaning |
---|---|
r | Treats newline character, the \n, as a literal. |
s | Copies a line into the history file. |
un | Reads from file descriptor n; the default is fd 0, or standard input. |
p | Reads a line of input from a coprocess. |
On Versions of ksh Newer than 1988: | |
A | Stores the fields as an array, index starting at zero. |
t sec | Puts a limit of seconds on the user's response time. |
d char | Used as an alternate delimiter for terminating input; newline is the default. |
(The Script) #!/bin/ksh # Scriptname: nosy print n "Are you happy? " 1 read answer print "$answer is the right response." print n "What is your full name? " 2 read first middle last print "Hello $first" print n "Where do you work? " 3 read 4 print I guess $REPLY keeps you busy! 5 read place?"Where do you live? " # New ksh read and print combined print Welcome to $place, $first $last (The Output) $ nosy Are you happy? Yes 1 Yes is the right response. 2 What is your full name? Jon Jake Jones Hello Jon 3 Where do you work? Tandem 4 I guess Tandem keeps you busy! 5 Where do you live? Timbuktu Welcome to Timbuktu, Jon Jones
EXPLANATION
|
Read and File Descriptors. When the system boots up, three files called streams (stdin, stdout, and stderr) are opened and assigned to an array of file descriptors. The first three file descriptors, 0, 1, and 2, are for standard input, standard output, and standard error, respectively. The next file descriptor available is file descriptor 3. The u option allows the read command to read directly from the file descriptor.
(The Command Line) 1 $ cat filex Captain Kidd Scarlett O'Hara 2 $ exec 3< filex # filex is assigned to file descriptor 3 for reading 3 $ read u3 name1 # read from filex and store input in variable, name1 4 $ print $name1 Captain Kidd 5 $ read u3 name2 $ print $name2 Scarlett O'Hara 6 $ exec 3<&- # Close file descriptor 3 7 $ read -u3 line ksh: read: bad file unit number
EXPLANATION
|
Reading through Files. Example 10.75 uses the read command with a while loop. The loop will iterate through the file one line at a time. When end of file is reached, the loop terminates. The files are opened with descriptors (units) for reading.
(The Files) 1 $ cat names Merry Melody Nancy Drew Rex Allen $ cat addresses 150 Piano Place 5 Mystery Lane 130 Cowboy Terrace ------------------------------------------------------------------ (The Script) #!/bin/ksh # Scriptname: readit 2 while read -u3 line1 && read -u4 line2 do 3 print "$line1:$line2" 4 done 3<$1 4<$2 ------------------------------------------------------------------ (The Command Line) 5 $ readit names addresses Merry Melody:150 Piano Place Nancy Drew:5 Mystery Lane Rex Allen:130 Cowboy Terrace ---------------------------------------------------------------
EXPLANATION
|
The Korn shell supports both integer and floating point arithmetic, but floating point arithmetic is available only on versions of the Korn shell newer than 1988. The typeset command is used for assigning types. See Table 10.22 for the typeset command.
typeset Command | Alias | Meaning |
---|---|---|
typeset i variable | integer variable | Variable is only allowed integer assignment. |
typeset i# | # is the base number for the integer. | |
On Versions of ksh Newer than 1988: | ||
typeset F variable | Floating point number assignment. | |
typeset E variable | float variable | Floating point number assignment. |
The Integer Type. Variables can be declared as integers with the typeset i command or its alias, integer. If you attempt to assign any string value, ksh returns an error. If you assign a floating point number, the decimal point and the fractional value will be truncated. The integer alias can be used instead of typeset i. Numbers can also be represented in different bases such as binary, octal, and hex.
1 $ typeset i num or integer num # integer is an alias for # typeset -i 2 $ num=hello /bin/ksh: hello: bad number 3 $ num=5 + 5 /bin/ksh: +: not found 4 $ num=5+5 $ echo $num 10 5 $ num=4*6 $ echo $num 24 6 $ num="4 * 6" $ echo $num 24 7 $ num=6.789 $ echo $num 6
EXPLANATION
|
Using Different Bases. Numbers can be represented in decimal (base 10), octal (base 8), and so forth, by using the typeset command and with the i option and the base number.[6]
1 $ num=15 2 $ typeset i2 num # binary $ print $num 2#1111 3 $ typeset i8 num # octal $ print $num 8#17 4 $ typeset i16 num # hex $ print $num 16#f 5 $ read number 2#1101 $ print $number 2#1101 6 $ typeset i number $ print $number 2#1101 7 $ typeset i10 number # decimal $ print $number 13 8 $ typeset i8 number # octal $ print $number 8#15
EXPLANATION
|
Listing Integers. The typeset command with only the i argument will list all preset integers and their values, as shown in the following display.
$ typeset i ERRNO=2 LINENO=1 MAILCHECK=600 OPTIND=1 PPID=4881 RANDOM=25022 SECONDS=47366 TMOUT=0 n=5 number=#15
Arithmetic Operators and the let Command. The let command is a Korn shell built-in command that is used to perform integer arithmetic. This replaces the Bourne shell integer testing. The alternative and preferred way to use the let command is with the (( )) operator.
Operator | Meaning |
---|---|
Unary minus. | |
! | Logical not. |
~ | Bitwise not. |
* / % | Multiply, divide, remainder. |
+ | Add, subtract. |
<< >> | Bitwise left shift, right shift. |
<= >= < > == != | Comparison operators. |
& ^ | | Bitwise and; exclusive or. |
&& || ! | Logical and; logical or; unary not. |
= | Assignment. |
*= /= %= += = <<= >>= &= ^= |= | Shortcut assignment. |
Note
The ++ and operators are supported on versions of ksh that are newer than 1988.
1 $ i=5 2 $ let i=i+1 $ print $i 6 3 $ let "i = i + 2" $ print $i 8 4 $ let "i+=1" $ print $i 9
EXPLANATION
|
(The Command Line) 1 $ (( i = 9 )) 2 $ (( i = i * 6 )) $ print $i 54 3 $ (( i > 0 && i <= 10 )) 4 $ print $? 1 $ j=100 5 $ (( i < j || i == 5 )) 6 $ print $? 0 7 $ if (( i < j && i == 54 )) > then > print True >fi True $
EXPLANATION
|
Command line arguments can be referenced in scripts with positional parameters; for example, $1 is set to the first argument, $2 to the second argument, and $3 to the third argument. Positional parameters can be reset with the set command. See Table 10.24.
Variable | Function |
---|---|
$0 | References the name of the script. |
$# | Holds the value of the number of positional parameters. |
$* | Contains a list of all the positional parameters. |
$@ | Means the same as $*, except when enclosed in double quotes. |
"$*" | Expands to a single argument, e.g., "$1 $2 $3". |
"$@" | Expands to separate arguments, e.g., "$1" "$2" "$3". |
The set Command and Positional Parameters. The set command sets the positional parameters. If the positional parameters have already been set, the set command will reset them, removing any values in the old list. To unset all of the positional parameters, use set .
(The Script) $ cat args #!/bin/ksh # Script to test command line arguments 1 print The name of this script is $0. 2 print The arguments are $*. 3 print The first argument is $1. 4 print The second argument is $2. 5 print The number of arguments is $#. 6 oldparameters=$* 7 set Jake Nicky Scott 8 print All the positional parameters are $*. 9 print The number of positional parameters is $#. 10 print $oldparameters 11 set -- 12 print Good bye for now, $1. 13 set $oldparameters 14 print $* (The Output) $ args a b c d 1 The name of this script is args. 2 The arguments are a b c d. 3 The first argument is a. 4 The second argument is b. 5 The number of arguments is 4. 8 All the positional parameters are Jake Nicky Scott. 9 The number of positional parameters is 3. 10 a b c d 12 Good-bye for now ,. 14 a b c d $
EXPLANATION
|
(How $* and $@ Differ) 1 $ set 'apple pie' pears peaches 2 $ for i in $* > do > echo $i > done apple pie pears peaches 3 $ set 'apple pie' pears peaches 4 $ for i in "$*" > do > echo $i > done apple pie pears peaches 5 $ set 'apple pie' pears peaches 6 $ for i in $@ > do > echo $i > done apple pie pears peaches 7 $ set 'apple pie' pears peaches 8 $ for i in "$@" # At last!! > do > echo $i > done apple pie pears peaches
EXPLANATION
|
The ? variable contains a number value (between 0 and 255) representing the exit status of the last command that exited. If the exit status is zero, the command exited with success; if nonzero, the command failed in some way. You can test the exit status of commands and use the test command to test the exit status of expressions.
The following examples illustrate how the exit status is tested. The single brackets are used in the Bourne shell, and although perfectly acceptable in the Korn shell, Dr. Korn provides you with the new double-bracket notation for testing expressions.
(The Command Line) 1 $ name=Tom 2 $ grep "$name" datafile Tom Savage:408-124-2345 3 $ print $? 0 # Success! 4 $ test $name = Tom 5 $ print $? 0 # Success 6 $ test $name != Tom $ print $? 1 # Failure 7 $ [ $name = Tom ] # Brackets instead of the test command 8 $ print $? 0 9 $ [[ $name = [Tt]?m ]] # New ksh test command 10 $ print $? 0
EXPLANATION
|
Conditional commands allow you to perform some task(s) based on whether or not a condition succeeds or fails. The if command is the simplest form of decision making. The if/else commands allow a two-way decision construct, and the if/elif/else commands allow a multiway decision construct.
The Korn shell expects a command to follow an if. The command can be a system command or a built-in command. The exit status of the command is used to evaluate the condition. To evaluate an expression, the built-in test command is used. This command is also linked to the [ and the [[ symbols. The Bourne shell encloses an expression in a set of single brackets: [ and ]. The Korn shell has a more sophisticated method for testing expressions. The expression is enclosed in double brackets: [[ and ]]. In the single brackets, the expansion of wildcards is not allowed; with the double brackets (Korn shell only), wildcard expansion is supported and a new set of operators have been added. The result of a command is tested, with zero status indicating success, and nonzero status indicating failure.
The Old test Command. The test command is used to evaluate conditional expressions, returning true or false. It returns zero exit status for true, and nonzero exit status for false. Either the test command or the brackets can be used. The Korn shell introduced a new way of testing expressions with double brackets. For backward-compatibility with the Bourne shell, the older form of test can be used with either the test command or the single brackets. However, the preferred method for Korn shell programmers is the new test with double brackets. A complete list to test operators (both old and new style) are listed in Table 10.25.
test | Tests For |
---|---|
String Testing: | |
string1 = string2 | string1 is equal to string2. |
string1 != string2 | string1 is not equal to string2. |
string | string is not null. |
z string | length of string is zero. |
n string | length of string is nonzero. |
Examples: test n $word or [ n $word ] test tom = sue or [ tom = sue ] | |
Integer Testing (Old-Style test Used with Bourne Shell): | |
int1 eq int2 | int1 is equal to int2. |
int1 ne int2 | int1 is not equal to int2. |
int1 gt int2 | int1 is greater than int2. |
int1 ge int2 | int1 is greater than or equal to int2. |
int1 lt int2 | int1 is less than int2. |
int1 le int2 | int1 is less than or equal to int2. |
Logical Operators (Old-Style test): | |
! | Not operator. |
a | And operator. |
o | Or operator. |
File Testing (Old-Style test): | |
b filename | Block special file. |
c filename | Character special file. |
d filename | Directory existence. |
f filename | File existence and not a directory. |
g filename | Set-group-ID is set. |
h filename | Symbolic link. |
k filename | Sticky bit is set. |
p filename | File is a named pipe. |
r filename | File is readable. |
s filename | File is nonzero size. |
u filename | Set-user-ID bit is set. |
w filename | File is writeable. |
x filename | File is executable. |
The New test Command. With the [[ ]] compound test command, additional operators are available. Wildcards can be used in string-matching tests, and many of the errors from the old test have been eliminated. New string test operators are listed in Table 10.26.
String Testing Operator | Tests For |
---|---|
string = pattern | string matches pattern.[a] |
string != pattern | string does not match pattern. |
string1 < string2 | ASCII value of string1 is less than string2. |
string1 > string2 | ASCII value of string1 is greater than string2. |
z string | string is zero in length, null parameter. |
n string | string is nonzero in length, nonnull parameter. |
[a] On versions newer than 1988, the == operator is permitted.
(The Script) read answer 1 if [[ $answer = [Yy]* ]] # Test for Yes or yes or Y or y, etc. then... Example: (The Script) guess=Noone 2 if [[ $guess != [Nn]o@(one|body) ]] # Test for Noone, noone then. . . # or Nobody, nobody... Example: (The Command Line) 3 [[ apples < oranges ]] print $? 0 4 [[ apples > oranges ]] print $? 1 5 $ name="Joe Shmoe" $ [ $name = "Abe Lincoln" ] # old style ksh: Shmoe: unknown test operator 6 $ [[ $name = "Abe Lincoln" ]] # new style $ echo $? 1
EXPLANATION
|
File Testing with Binary Operators. The binary operators for testing files require two operands (i.e., a file on either side of the operator). See Table 10.27 for a list of binary file testing operators.
Operators | Tests For |
---|---|
Binary File Testing | |
file1 nt file2 | True if file1 is newer than file2. |
file1 ot file2 | True if file1 is older than file2. |
file1 ef file2 | True if file1 is another name for file2. |
Logical Operators. The Korn shell, like C, provides logical testing of the truth or falsity of expressions. They are listed in Table 10.28.
Operators | Tests For |
---|---|
&& | The and operator evaluates the expression on the left-hand side of &&; if true, the expression on the right side of && is tested and must also be true. If one expression is false, the expression is false. The && operator replaces a; e.g., (( ( $x && $y ) > 5 )). |
|| | The or operator evaluates the expression on the left-hand side of the || operator; if true, the expression is true; if false, the expression on the right-hand side of the || is evaluated; if true, the expression is true. Only if both expressions are false will the expression evaluate to false. The || operator replaces o; e.g., (( ( $x || $y ). |
File Testing. The Korn shell provides a number of built-in test commands for checking the attributes of files, such as existence, type, permissions, etc. The file testing options (also called flags) are listed in Table 10.29.
test Flag | Tests For |
---|---|
Korn Shell Only: | |
a file | file exists. |
e file | file exists (versions newer than 1988). |
L file | file exists and is a symbolic link. |
O file | You are the owner of file. |
G file | Your group ID is the same as file's. |
S file | file exists and is a socket. |
Bourne and Korn Shells: | |
r file | file exists and is readable. |
w fle | file exists and is writeable. |
x file | file exists and is executable. |
f file | file exists and is not a directory. |
d file | file exists and is a directory. |
b file | file exists and is a block special file. |
c file | file exists and is a character special file. |
p file | file exists and is a named pipe. |
u file | file exists and is setuid. |
g file | file exists and is setgid. |
k file | file exists and sticky bit is set. |
s file | file has a nonzero size. |
(The Script) 1 file=/etc/passwd 2 if [[ -f $file && ( r $file || w $file) ]] then 3 print $file is a plain file and is either readable or writeable fi
EXPLANATION
|
The if Command. The simplest form of conditional is the if command. The command following the if keyword is executed and its exit status is returned. If the exit status is zero, the command succeeded and the statement(s) after the then keyword are executed.
In the C shell and C language, the expression following the if command is a Boolean-type expression. But in the Bourne and Korn shells, the statement following the if is a command or group of commands. The exit status of the last command of the if line is used to determine whether or not to continue and execute commands under the then statement. If the exit status of the last command on the if line is zero, the commands under the then statement are executed. The fi terminates the command list to be executed after the then. If the exit status is nonzero, meaning that the command failed in some way, the statement(s) after the then statement are ignored and control goes to the line directly after the fi statement.
Conditional commands can be nested. Every if must have a corresponding fi. The fi is paired with the closest if. Using indentation to format your if blocks helps when debugging your programs.
FORMATif command then # Testing command exit status command command fi ------------------------------------ if test expression then # Using the test command to test expressions command fi or if [ expression ] then # Using the old-style test command-- command # brackets replace the word test fi ---------------------------------- if [[ expression ]] then # New-style brackets for testing expressions command fi ---------------------------------------------- if command then ... if command then ... if command # Nested conditionals then ... fi fi fi |
1 if ypmatch $name passwd > /dev/null 2>&1 2 then echo Found $name! 3 fi
EXPLANATION
|
Using the Old-Style Bourne test. If you have been programming in the Bourne shell, the Korn shell is backward-compatible, allowing your Bourne shell scripts to be executed properly by the Korn shell. Many Bourne shell programmers, when converting to Korn shell, still use the old-style test command when evaluating expressions. If you are reading or maintaining scripts, you may find the old syntax alive and well. Therefore, a brief discussion of the old syntax may help you, even if you are writing your own scripts with the new Korn shell test command.
#!/bin/ksh # Scriptname: are_you_ok 1 print "Are you ok (y/n) ?" read answer 2 if [ "$answer" = Y -o "$answer" = y ] # Old-style test then print "Glad to hear it." 3 fi
EXPLANATION
|
Using the New-Style Korn test. The new Korn shell-style testing allows expressions to contain shell metacharacters and Korn shell operators such as && and ||.
#!/bin/ksh # Scriptname: are_you_ok2 1 print "Are you ok (y/n) ?" read answer 2 if [[ "$answer" = [Yy]* ]] # New-style test then print "Glad to hear it." 3 fi
EXPLANATION
|
Using the Old-Style Bourne test with Numbers. To test numeric expressions, the old-style Bourne shell test command and its operators are still acceptable in the Korn shell, but the new-style let command is preferred.
1 if [ $# -lt 1 ] then print "$0: Insufficient arguments " 1>&2 exit 1 2 fi
EXPLANATION
|
The let Command and Testing Numbers. Although it is still acceptable to use single square brackets and old-style Bourne shell numeric operators for testing numeric expressions, the preferred Korn shell method is to use the double parentheses and the new C-language style numeric operators when testing numeric expressions. Note that the double brackets are only used for testing string expressions and for file tests (see Table 10.29).
1 if (( $# < 1 )) then print "$0: Insufficient arguments " 1>&2 exit 1 2 fi
EXPLANATION
|
The if/else Command. The if/else command allows a two-way decision-making process. If the command after the if fails, the commands after the else are executed.
FORMATif command then command(s) else command(s) fi |
1 if ypmatch "$name" passwd > /dev/null 2>&1 2 then print Found $name! 3 else 4 print "Can't find $name." exit 1 5 fi
EXPLANATION
|
The if/elif/else Command. The if/elif/else command allows a multiway decision-making process. If the command following the if fails, the command following the elif is tested. If that command succeeds, the commands under its then statement are executed. If the command after the elif fails, the next elif command is checked. If none of the commands succeed, the else commands are executed. The else block is called the default.
FORMATif command then command(s) elif command then commands(s) elif command then command(s) else command(s) fi |
FORMATif [[ string expression ]] or if (( numeric expression )) then command(s) elif [[ string expression ]] or elif (( numeric expression )) then commands(s) elif [[ string expression ]] or elif(( numeric expression )) then command(s) else command(s) fi |
(The Script) #!/bin/ksh # Scriptname: tellme 1 read age?"How old are you? " 2 if (( age < 0 || age > 120 )) then print "Welcome to our planet! " exit 1 fi 3 if (( age >= 0 && age < 13 )) then print "A child is a garden of verses" elif (( age > 12 && age < 20 )) then print "Rebel without a cause" elif (( age >= 20 && age < 30 )) then print "You got the world by the tail!!" elif (( age >= 30 && age < 40 )) then print "Thirty something..." 4 else print "Sorry I asked" 5 fi (The Output) $ tellme How old are you? 200 Welcome to our planet! $ tellme How old are you? 13 Rebel without a cause $ tellme How old are you? 55 Sorry I asked
EXPLANATION
|
The exit Command. The exit command is used to terminate the script and get back to the command line. You may want the script to exit if some condition does not test true. The argument to the exit command is an integer, ranging from zero to 255. When the program exits, the exit number is stored in the shell's ? variable.
(The Script) #!/bin/ksh # Scriptname: filecheck # Purpose: Check to see if a file exists,what type it is, # and its permissions. 1 file=$1 # Variable is set to first command line argument 2 if [[ ! -a $file ]] then print "$file does not exist" exit 1 fi 3 if [[ -d $file ]] then print "$file is a directory" 4 elif [[ -f $file ]] then 5 if [[ -r $file && -w $file && -x $file ]] then print "You have read, write, and execute permission on file $file" else 6 print "You don't have the correct permissions" exit 2 fi else 7 print "$file is neither a file nor a directory. " exit 3 8 fi (The Command Line) 9 $ filecheck testing testing does not exist 10 $ echo $? 1
EXPLANATION
|
The null Command. The null command is a colon. It is a built-in, do-nothing command that returns an exit status of zero. It is used as a placeholder after an if command when you have nothing to say, but need a command or the program will produce an error message because it requires something after the then statement. Often the null command is used as an argument to the loop command to make the loop a forever loop or for testing variable expression modifiers such as {EDITOR: /bin/vi}.
(The Script) 1 name=Tom 2 if grep "$name" databasefile > /dev/null 2>&1 then 3 : 4 else print "$1 not found in databasefile" exit 1 fi
EXPLANATION
|
(The Script) 1 : ${EDITOR:=/bin/vi} 2 echo $EDITOR
EXPLANATION
|
The case command is a multiway branching command used as an alternative to the if/elif commands. The value of the case variable is matched against value1, value2, and so forth until a match is found. When a value matches the case variable, the commands following the value are executed until the double semicolons are reached. Then, instruction starts after the word esac (case spelled backwards).
If a case variable is not matched, the program executes commands after the *) , the default value, until the double semicolons or esac is reached. The *) value serves the same purpose as the else statement in if/else conditionals. The case values can use shell wildcards and the vertical bar (pipe symbol ) for oring two values.
FORMATcase variable value1) command(s);; value2) command(s);; *) command(s);; esac |
(The Script) #!/bin/ksh # Scriptname: xtermcolor # Sets the xterm foreground color (the color of the prompt and # input typed for interactive windows. 1 read color?"Choose a foreground color for your terminal?" 2 case "$color" in 3 *[Bb]l??) 4 xterm -fg blue -fn terminal & 5 ;; 6 *[Gg]reen) xterm -fg darkgreen -fn terminal & ;; 7 red | orange) # The vertical bar means "or" xterm -fg "$color" -fn terminal & ;; 8 *) xterm -fn terminal & # default ;; 9 esac 10 print "Out of case..."
EXPLANATION
|
The case Command and the here document. Often the here document is used to create a menu. After the user has selected a choice from the menu, the case command is used to match against one of the choices. The Korn shell also provides a select loop for creating menus.
(The .profile File) print "Select a terminal type " 1 cat << EOF 1) vt120 2) wyse50 3) ansi 4) sun 2 EOF 3 read TERM 4 case "$TERM" in 1) export TERM=vt120 ;; 2) export TERM=wyse50 ;; 3) export TERM=ansi ;; *) export TERM=sun ;; 5 esac print "TERM is $TERM"
EXPLANATION
|
The looping commands are used to execute a command or group of commands a set number of times, or until a certain condition is met. The Korn shell has four types of loops: the for loop, while loop, until loop, and select loop.
The for Command. The for looping command is used to execute commands for each member of a set of arguments. You might use this loop to execute the same commands on a list of files or usernames. The for command is followed by a user-defined variable, the keyword in, and a list of words. The first time in the loop, the first word from the wordlist is assigned to the variable, and then shifted off. The next time around the loop, the second word is assigned to the variable, and so on. The body of the loop starts at the do keyword and ends at the done keyword. When all of the words in the list have been shifted off, the loop ends and program control continues after the done keyword.
FORMATfor variable in wordlist do command(s) done |
(The Script) 1 for pal in Tom Dick Harry Joe 2 do 3 print "Hi $pal" 4 done 5 print "Out of loop" (The Output) Hi Tom Hi Dick Hi Harry Hi Joe Out of loop
EXPLANATION
|
(The Command Line) 1 $ cat mylist tom patty ann jake ------------------------------------------------------------- (The Script) 2 for person in $(< mylist) #same as for person in 'cat mylist' do 3 mail $person < letter print $person was sent a letter. 4 done 5 print "The letter has been sent."
EXPLANATION
|
1 for file in *.c 2 do if [[ -f $file ]] ; then cc $file -o ${file%.c} fi done
EXPLANATION
|
The $* and $@ Variables in Wordlists. When expanded, the $* and $@ are the same unless enclosed in double quotes. "$*" evaluates to one string, whereas "$@" evaluates to a list of separate words.
(The Script) #!/bin/ksh 1 for name in $* # or for name in $@ 2 do echo Hi $name 3 done ----------------------------------------------------------------- (The Command Line) $ greet Dee Bert Lizzy Tommy Hi Dee Hi Bert Hi Lizzy Hi Tommy
EXPLANATION
|
The while Command. The while evaluates the command immediately following it, and if its exit status is zero, the commands in the body of the loop (commands between do and done) are executed. When the done keyword is reached, control is returned to the top of the loop and the while command checks the exit status of the command again. Until the exit status of the command being evaluated by the while becomes nonzero, the loop continues. When the exit status reaches nonzero, program execution starts after the done keyword. If the exit status never becomes nonzero, the loop goes around and around infinitely. (Of course, pressing Control-C or Control-\ will stop the looping.)
FORMATwhile command do command(s) done |
(The Script) 1 num=0 # Initialize num 2 while (( num < 10 )) # Test num with the let do print -n $num 3 (( num=num + 1 )) # Increment num done print "\nAfter loop exits, continue running here" (The Output) 0123456789 After loop exits, continue running here
EXPLANATION
|
(The Script) #!/bin/ksh # Scriptname: quiz 1 read answer?"Who was the U.S. President in 1992? " 2 while [[ $answer != "Bush" ]] 3 do print "Wrong try again!" 4 read answer 5 done 6 print Good guess! (The Output) $ quiz Who was the U.S. President in 1992? George Wrong try again! Who was the U.S. President in 1992? I give up Wrong try again! Who was the U.S. President in 1992? Bush Good guess!
EXPLANATION
|
(The Script) 1 go=1 print Type q to quit. 2 while let go or (( go )) do print I love you. read word 3 if [[ $word = [qQ]* ]] then print "I'll always love you" 4 go=0 fi 5 done (The Output) $ sayit Type q to quit. I love you. I love you. I love you. I love you. I love you. q I'll always love you $
EXPLANATION
|
The until Command. The until command is used like the while command, but evaluates the exit status in the opposite way. The until evaluates the command immediately following it, and if its exit status is not zero, the commands in the body of the loop (commands between do and done) are executed. When the done keyword is reached, control is returned to the top of the loop and the until command checks the exit status of the command again. Until the exit status of the command being evaluated by until becomes zero, the loop continues. When the exit status reaches zero, program execution starts after the done keyword.
FORMATuntil command do command(s) done |
#!/bin/ksh 1 until who | grep linda 2 do sleep 5 3 done talk linda@dragonwings
EXPLANATION
|
#!/bin/ksh 1 hour=0 2 until (( hour > 23 )) do 3 case "$hour" in [0-9]|1[0-1]) print "Good morning!" ;; 12) print "Lunch time" ;; 1[3-7]) print "Siesta time" ;; *) print "Good night" ;; esac 4 (( hour+=1 )) 5 done
EXPLANATION
|
The select Command and Menus. The here document is an easy method for creating menus, but the Korn shell introduces a new loop, called the select loop, which is used primarily for creating menus. A menu of numerically listed items is displayed to standard error. The PS3 prompt is used to prompt the user for input; by default, PS3 is #?. After the PS3 prompt is displayed, the shell waits for user input. The input should be one of the numbers in the menu list. The input is stored in the special Korn shell REPLY variable. The number in the REPLY variable is associated with the string to the right of the parentheses in the list of selections.[7]
The case command is used with the select command to allow the user to make a selection from the menu and, based on that selection, execute commands. The LINES and COLUMNS variables can be used to determine the layout of the menu items displayed on the terminal. The output is displayed to standard error, each item preceded by a number and closing parenthesis, and the PS3 prompt is displayed at the bottom of the menu. Since the select command is a looping command, it is important to remember to use either the break command to get out of the loop, or the exit command to exit the script.
FORMATselect var in wordlist do command(s) done |
(The Script) #!/bin/ksh # Program name: goodboys 1 PS3="Please choose one of the three boys : " 2 select choice in tom dan guy 3 do 4 case $choice in tom) print Tom is a cool dude! 5 break;; # break out of the select loop 6 dan | guy ) print Dan and Guy are both sweethearts. break;; *) 7 print " $REPLY is not one of your choices" 1>&2 print "Try again." ;; 8 esac 9 done (The Command Line) $ goodboys 1) tom 2) dan 3) guy Please choose one of the three boys : 2 Dan and Guy are both sweethearts. $ goodboys 1) tom 2) dan 3) guy Please choose one of the three boys : 4 4 is not one of your choices Try again. Please choose one of the three boys : 1 Tom is a cool dude! $
EXPLANATION
|
(The Script) #!/bin/ksh # Program name: ttype # Purpose: set the terminal type # Author: Andy Admin 1 COLUMNS=60 2 LINES=1 3 PS3="Please enter the terminal type: " 4 select choice in wyse50 vt200 vt100 sun do 5 case $REPLY in 1) 6 export TERM=$choice print "TERM=$choice" break;; # break out of the select loop 2 | 3 ) export TERM=$choice print "TERM=$choice" break;; 4) export TERM=$choice print "TERM=$choice" break;; *) 7 print "$REPLY is not a valid choice. Try again" 1>&2 ;; esac 8 done (The Command Line) $ ttype 1) wyse50 2) vt200 3) vt100 4) sun Please enter the terminal type : 4 TERM=sun $ ttype 1) wyse50 2) vt200 3) vt100 4) sun Please enter the terminal type : 3 TERM=vt100 $ ttype 1) wyse50 2) vt200 3) vt100 4) sun Please enter the terminal type : 7 7 is not a valid choice. Try again. Please enter the terminal type: 2 TERM=vt200
EXPLANATION
|
Looping Commands. If some condition occurs, you may want to break out of a loop, return to the top of the loop, or provide a way to stop an infinite loop. The Korn shell provides loop control commands to control loops.
The shift Command. The shift command shifts the parameter list to the left a specified number of times. The shift command without an argument shifts the parameter list once to the left. Once the list is shifted, the parameter is removed permanently. Often the shift command is used in while loops when iterating through a list of positional parameters.
FORMATshift [n] |
(Without a Loop) (The Script) #!/bin/ksh # Scriptname: doit0 1 set joe mary tom sam 2 shift 3 print $* 4 set $(date) 5 print $* 6 shift 5 7 print $* 8 shift 2 (The Output) $ doit0 3 mary tom sam 5 Sun Sep 9 10:00:12 PDT 2001 7 2001 8 ksh: shift: bad number
EXPLANATION
|
(With a Loop) (The Script) #!/bin/ksh # Usage: doit [args] 1 while (( $# > 0 )) do 2 print $* 3 shift 4 done (The Command Line) $ doit a b c d e a b c d e b c d e c d e d e e
EXPLANATION
|
The break Command. The built-in break command is used to force immediate exit from a loop, but not from a program. (To leave a program, the exit command is used.) After the break command is executed, control starts after the done keyword. The break command causes an exit from the innermost loop, so if you have nested loops, the break command takes a number as an argument, allowing you to exit out of any number of outer loops. The break is useful for exiting from an infinite loop.
Formatbreak [n] |
EXPLANATION
|
The continue Command. The continue command starts back at the top of the loop if some condition becomes true. All commands below the continue will be ignored. The continue command returns control to the top of the innermost loop; if nested within a number of loops, the continue command may take a number as its argument. Control can be started at the top of any number of outer loops.
FORMATcontinue [n] |
EXPLANATION
|
Nested Loops. If using nested loops, the break and continue commands let you control which loop to terminate.
EXPLANATION
|
I/O Redirection and Loops. The Korn shell allows you to use redirection and pipes in loops. Unlike the Bourne shell, the loop runs in this shell, not a subshell. Variables set within the loop will still be set when the loop exits.
Redirect the Output of a Loop to a File. Instead of sending the output of a loop to the screen, it can be redirected to a file or a pipe. See Example 10.113.
(The Command Line) 1 $ cat memo abc def ghi ------------------------------------------------------------------ (The Script) #!/bin/ksh # Program name: numberit # Put line numbers on all lines of memo 2 if (( $# < 1 )) then print "Usage: $0 filename " >&2 exit 1 fi 3 integer count=1 # Initialize count 4 cat $1 | while read line # Input is coming from memo do 5 (( count == 1 )) && print "Processing file $1..." > /dev/tty 6 print $count $line 7 (( count+=1 )) 8 done > tmp$$ # Output is going to a temporary file 9 mv tmp$$ $1 (The Command Line) 10 $ numberit memo Processing file memo... 11 $ cat memo 1 abc 2 def 3 ghi
EXPLANATION
|
Pipe the Output of a Loop to a UNIX Command. The output of a loop can be redirected from the screen to a pipe. See Example 10.114.
(The Script) 1 for i in 7 9 2 3 4 5 2 do print $i 3 done | sort n (The Output) 2 3 4 5 7 9
EXPLANATION
|
Running Loops in the Background. If the loop is going to take a while to process, it can be run as a background job so that the rest of the program can continue.
1 for person in bob jim joe sam do 2 mail $person < memo 3 done &
EXPLANATION
|
The exec Command and Loops. The exec command can be used to close standard input or output without creating a subshell.
(The File) 1 cat tmp apples pears bananas peaches plums ----------------------------------------------------------- (The Script) #!/bin/ksh # Scriptname: speller # Purpose: Check and fix spelling errors in a file # 2 exec < tmp # Opens the tmp file 3 while read line # Read from the tmp file do 4 print $line 5 print n "Is this word correct? [Y/N] " 6 read answer < /dev/tty # Read from the terminal case $answer in [Yy]*) continue ;; *) print "New word? " 7 read word < /dev/tty sed "s/$line/$word/" tmp > error mv error tmp 8 print $word has been changed. ;; esac done
EXPLANATION
|
The IFS and Loops. The IFS, the shell's internal field separator, evaluates to spaces, tabs, and the newline character. It is used as a word (token) separator for commands that parse lists of words such as read, set, for, and select. It can be reset by the user if a different separator will be used in a list. It is a good idea to save the original value of the IFS in another variable before changing it. Then it is easy to return to its default value.
(The Script) #!/bin/ksh # Script is called runit. # IFS is the internal field separator and defaults to # spaces, tabs, and newlines. # In this script it is changed to a colon. 1 names=Tom:Dick:Harry:John 2 OLDIFS="$IFS" # Save the original value of IFS 3 IFS=":" 4 for persons in $names do 5 print Hi $persons done 6 IFS="$OLDIFS" # Reset the IFS to old value 7 set Jill Jane Jolene # Set positional parameters 8 for girl in $* do print Howdy $girl done (The Output) $ runit Hi Tom Hi Dick Hi Harry Hi John Howdy Jill Howdy Jane Howdy Jolene
EXPLANATION
|
Korn shell arrays are one-dimensional arrays that may contain up to 1,024 (size varies) elements consisting of words or integers. The index starts at zero. Each element of an array can be set or unset individually. Values do not have to be set in any particular order. For example, you can assign a value to the tenth element before you assign a value to the first element. An array can be set using the set command with the A option.
Associative arrays are supported under versions of the Korn shell that are more recent than 1988.
(The Command Line) 1 $ array[0]=tom $ array[1]=dan $ array[2]=bill 2 $ print ${array[0]} # Curly braces are required. tom 3 $ print ${array[1]} dan 4 $ print ${array[2]} bill 5 $ print ${array[*]} # Display all elements. tom dan bill 6 $ print ${#array[*]} # Display the number of elements. 3
EXPLANATION
|
(At The Command Line) 1 $ typeset i ints[4] # Declare an array of four integers. 2 $ ints[0]=50 $ ints[1]=75 $ ints[2]=100 3 $ ints[3]=happy ksh: happy: bad number
EXPLANATION
|
Creating Arrays with the set Command. You can assign the values of an array using the set command. The first word after the A option is the name of the array; the rest of the words are the elements of the array.
(The Command Line) 1 $ set A fruit apples pears peaches 2 $ print ${fruit[0]} apples 3 $ print ${fruit[*]} apples pears peaches 4 $ fruit[1]=plums 5 $ print ${fruit[*]} apples plums peaches
EXPLANATION
|
Korn shell functions are similar to those used in the Bourne shell, and are used to modularize your program. A function is a collection of one or more commands that can be executed simply by entering the function's name, similar to a built-in command. Here is a review of some of the important rules about using functions.
The Korn shell executes built-in commands first, then functions, and then executables. Functions are read into memory once when they are defined, not every time they are referenced.
A function must be defined before it is used; therefore, it is best to place function definitions at the beginning of the script.
The function runs in the current environment; it shares variables with the script that invoked it, and lets you pass arguments by setting them as positional parameters. The present working directory is that of the calling script. If you change the directory in the function, it will be changed in the calling script.
In the Korn shell, you can declare local variables in the function using the typeset command. Ksh functions can be exported to subshells.
The return statement returns the exit status of the last command executed within the function or the value of the argument given, and cannot exceed a value of 255.
To list functions and definitions, use the preset alias, functions.
Traps are local to functions and will be reset to their previous value when the function exits (not so with the Bourne shell).
Functions can be recursive, that is, call themselves. Recursion should be handled carefully. The Korn shell will warn you otherwise with the message, recursion too deep.
Functions can be autoloaded; they are defined only if referenced. If never referenced, they are not loaded into memory.
Versions of the Korn shell that are more recent than 1988 also support discipline functions, passing variables by reference, and compound variables. A built-in command is no longer found before a function of the same name. In older versions it was necessary to use a combination of aliases and functions to write a function that would override a built-in command.[8]
Defining Functions. A function must be defined before it can be invoked. Korn shell functions are defined with the keyword function preceding the function name. The curly braces must have a space on the inside of each brace. (Please see Bourne shell functions for the older-style function definition, still compatible in Korn shell scripts.)
FORMATfunction function_name { commands; commands; } |
function usage { print "Usage $0 [-y] [-g] " ; exit 1; }
EXPLANATIONThe function name is usage. It is used to print a diagnostic message and exit the script if the script does not receive the proper arguments, either y or g. |
Listing and Unsetting Functions. To list local function definitions, type: typeset f. To list exported function definitions, type: typeset fx. To unset a function, type: unset f function_name. See the typeset command, Table 10.30.
Local Variables and the Return Value. The typeset command can be used to create local variables. These variables will be known only in the function where they are created. Once out of the function, the local variables are undefined.
The return value of a function is really just the value of the exit status of the last command in the script unless a specific return command is used. If a value is assigned to the return command, that value is stored in the ? variable. It can hold an integer value between 0 and 255. Because the return command is limited to returning only integer values, you can use command substitution to return the output of a function and assign the output to a variable, just as you would if getting the output of a UNIX command.
EXPLANATION
|
(Using Command Substitution) (The Script) # Scriptname: do_square #!/bin/ksh 1 function square { (( sq = $1 * $1 )) print "Number to be squared is $1." 2 print "The result is $sq " } 3 read number?"Give me a number to square. " 4 value_returned=$(square $number) 5 print $value_returned (The Output) $ do_square 5 Number to be squared is 10. The result is 100
EXPLANATION
|
Exported Functions. Function definitions are not inherited by subshells unless you define them in the ENV file with the typeset command, e.g., typeset fx function_names.
You can export functions with typeset fx from the current Korn shell to a script, or from one script to another, but not from one invocation of ksh to the next (e.g., a separate invocation means that if you type ksh at the prompt, a brand new shell is started up). Exported function definitions will not be inherited by the new shell.
(The First Script) $ cat calling_script #!/bin/ksh 1 function sayit { print "How are ya $1?" ; } 2 typeset fx sayit # Export sayit to other scripts 3 sayit Tommy 4 print "Going to other script" 5 other_script # Call other_script print "Back in calling script" **************************************************************** (The Second Script) $ cat other_script NOTE: This script cannot be invoked with #!/bin/ksh 6 print "In other script " 7 sayit Dan 8 print "Returning to calling script" (The Output) $ calling_script 3 How are ya Tommy? 4 Going to other script 6 In other script 7 How are ya Dan? 8 Returning to calling script Back in calling script
EXPLANATION
|
The typeset command is used to display function attributes.
Option | What It Does |
---|---|
typeset f | Displays all functions and their values. Must have a history file, as all function definitions are stored there. |
typeset +f | Displays just function names. |
typeset fx | Displays all function definitions that will be exported across shell scripts, but not as a separate invocation of ksh. |
typeset fu func | func is the name of a function that has not yet been defined. |
Autoloaded Functions. An autoloaded function is not loaded into your program until you reference it. The autoloaded function can be defined in a file somewhere else and the definition will not appear in your script, allowing you to keep the script small and compact. To use autoload, you need to set the FPATH variable in your ENV file. The FPATH variable contains a search path for directories containing function files. The files in this directory have the same names as the functions defined within them.
The autoload alias for typeset fu specifies that the function names that have not yet been defined are to be autoloaded functions. After the autoload command is executed with the function as its argument, you must invoke the function to execute the commands contained in it. The primary advantage of autoloading functions is better performance, since the Korn shell does not have to read the function definition if it has never been referenced.[9]
(The Command Line) 1 $ mkdir functionlibrary 2 $ cd functionlibrary 3 $ vi foobar (In Editor) 4 function foobar { pwd; ls; whoami; } # function has the same # name as the file. (In .profile File) 5 export FPATH=$HOME/functionlibrary # This path is searched for # functions. (In Your Script) 6 autoload foobar 7 foobar
EXPLANATION
|
A number of functions can be stored in one file; for example, calculation functions may be contained in a file called math. Since the function must have the same name as the file in which it is stored, you may create hard links to the function file. Each function name will be a link to the file in which the function is defined. For example, if a function in the math file is called square, use the UNIX ln command to give the math file another name, square. Now the math file and square file can be referenced, and in either case you are referencing the file by the corresponding function name. Now the square function can be autoloaded by its own name.
(The Command Line) 1 $ ln math square add divide 2 $ ls -i 12256 add 12256 math 12256 square 12256 divide 3 $ autoload square; square
EXPLANATION
|
While your program is running, if you press Control-C or Control-\, the program terminates as soon as the signal arrives. There are times when you would rather not have the program terminate immediately after the signal arrives. You could arrange to ignore the signal and keep running, or perform some sort of cleanup operation before actually exiting the script. The trap command allows you to control the way a program behaves when it receives a signal.
A signal is defined as an asynchronous message that consists of a number that can be sent from one process to another, or by the operating system to a process if certain keys are pressed or if something exceptional happens.[10] The trap command tells the shell to terminate the command currently in execution upon the receipt of a signal. If the trap command is followed by commands within single quotes, those commands will be executed upon receipt of a specified signal. Use the command kill l to get a list of all signals and the numbers corresponding to them.
FORMATtrap 'command; command' signal |
trap 'rm tmp*$$; exit 1' 1 2 15
EXPLANATIONWhen any of the signals 1 (hangup), 2 (interrupt), or 15 (software termination) arrives, remove all the tmp files and then exit. |
If an interrupt comes in while the script is running, the trap command lets you handle the interrupt signal in several ways. You can let the signal behave normally (default), ignore the signal, or create a handler function to be called when the signal arrives. See Table 10.31 for a list of signal numbers and their corresponding names.
1) HUP | 12) SYS | 23) POLL |
2) INT | 13) PIPE | 24) XCPU |
3) QUIT | 14) ALRM | 25) XFSZ |
4) ILL | 15) TERM | 26) VTALRM |
5) TRAP | 16) URG | 27) PROF |
6) IOT | 17) STOP | 28) WINCH |
7) EMT | 18) TSTP | 29) LOST |
8) FPE | 19) CONT | 30) USR1 |
9) KILL | 20) CHLD | 31) USR2 |
10) BUS | 21) TTIN | |
11) SEGV | 22) TTOU |
[a] The output of this command may differ slightly with the operating system.
Pseudo or Fake Signals. The three fake signals are not real signals, but are generated by the shell to help debug a program. They are treated like real signals by the trap command and defined in the same way. See Table 10.32 for a list of pseudo signals.
Signal | What It Does |
---|---|
DEBUG | Executes trap commands after every script command. |
ERR | Executes trap commands if any command in the script returns a nonzero exit status. |
0 or EXIT | Executes trap commands if the shell exits. |
Signal names such as HUP and INT are normally prefixed with SIG, for example, SIGHUP, SIGINT, and so forth. The Korn shell allows you to use symbolic names for the signals, which are the signal names without the SIG prefix, or you can use the numeric value for the signal. See Example 10.128.
Resetting Signals. To reset a signal to its default behavior, the trap command is followed by the signal name or number. Traps set in functions are local to functions; that is, they are not known outside the function where they were set.
trap 2 or trap INT
EXPLANATIONResets the default action for signal 2, SIGINT. The default action is to kill the process when the interrupt key (Control-C) is pressed. |
Ignoring Signals. If the trap command is followed by a pair of empty quotes, the signals listed will be ignored by the process.
trap " " 1 2 or trap "" HUP INT
EXPLANATIONSignals 1 (SIGHUP) and 2 (SIGINT) will be ignored by the shell process. |
Listing Traps. To list all traps and the commands assigned to them, type trap.
(The Script) #!/bin/ksh # Scriptname: trapping # Script to illustrate the trap command and signals # Can use the signal numbers or ksh abbreviations seen # below. Cannot use SIGINT, SIGQUIT, etc. 1 trap 'print "Control C will not terminate $PROGRAM."' INT 2 trap 'print "Control \ will not terminate $PROGRAM."' QUIT 3 trap 'print "Control Z will not terminate $PROGRAM."' TSTP 4 print "Enter any string after the prompt.\ When you are ready to exit, type \"stop\"." 5 while true do 6 print n "Go ahead...> " 7 read 8 if [[ $REPLY = [Ss]top ]] then 9 break fi 10 done (The Output) $ trapping 4 Enter any string after the prompt. When you are ready to exit, type "stop". 6 Go ahead...> this is it^C 1 Control C will not terminate trapping. 6 Go ahead...> this is it again^Z 3 Control Z will not terminate trapping. 6 Go ahead...> this is never it^\ 2 Control \ will not terminate trapping. 6 Go ahead...> stop $
EXPLANATION
|
EXPLANATION
|
Traps and Functions. If trap is used in a function, the trap and its commands are local to the function.
(The Script) #!/bin/ksh 1 function trapper { print "In trapper" 2 trap 'print "Caught in a trap!"' INT print "Got here." sleep 25 } 3 while : do print "In the main script" 4 trapper # Call the function 5 print "Still in main" sleep 5 print "Bye" done ------------------------------------------------------ (The Output) $ functrap In the main script In trapper Got here. ^CCaught in a trap! $
EXPLANATION
|
A coprocess is a special two-way pipeline that allows shell scripts to write to the standard input of another command and to read from its standard output. This provides a way to create a new interface for an existing program. The append operator, |&, is placed at the end of the command to initiate the command as a coprocess. Normal redirection and background processing should not be used on coprocesses. The print and read commands require a p switch to read from and write to a coprocess. The output must be sent to standard output and have a newline at the end of each message of output. The standard output must be flushed after each message is sent to standard output. You can run multiple coprocesses by using the exec command with the >&p or <&p operator. To open file descriptor 4 as a coprocess, you would enter exec 4>&p.
(The Script) #!/bin/ksh # Scriptname: mycalculator # A simple calculator uses the bc command to perform the # calculations # Since the shell performs operations on integers only, # this program allows # you to use floating point numbers by writing to and reading # from the bcprogram. 1 cat << EOF ************************************************** 2 WELCOME TO THE CALCULATOR PROGRAM ************************************************* 3 EOF 4 bc |& # Open coprocess 5 while true do 6 print "Select the letter for one of the operators below " 7 cat <<- EOF a) + s) m) * d) / e) ^ EOF 8 read op 9 case $op in a) op="+";; s) op=" ";; m) op="*";; d) op="/";; e) op="^";; *) print "Bad operator" continue;; esac 10 print p scale=3 # write to the coprocess 11 print "Please enter two numbers: " # write to standard out 12 read num1 num2 # read from standard in 13 print p "$num1" "$op" "$num2" # write to the coprocess 14 read p result # read from the coprocess 15 print $result 16 print n "Continue (y/n)? " 17 read answer 18 case $answer in [Nn]* ) 19 break;; esac 20 done 21 print Good bye (The Output) $ mycalculator ************************************************** 1 WELCOME TO THE CALCULATOR PROGRAM ************************************************* 6 Select one of the operators below 7 a) + s) m) * d) / e) ^ e 11 Please enter two numbers: 2.3 4 27.984 16 Continue (y/n)? y 6 Select one of the operators below 7 a) + s) m) * d) / e) ^ d 11 Please enter two numbers: 2.1 4.6 0.456 16 Continue (y/n)? y 6 Select one of the operators below 7 a) + s) m) * d) / e) ^ m 11 Please enter two numbers: 4 5 20 16 Continue (y/n)? n Good bye
EXPLANATION
|
By turning on the noexec option or using the n argument to the ksh command, you can check the syntax of your scripts without really executing any of the commands. If there is a syntax error in the script, the shell will report the error. If there are no errors, nothing is displayed.
The most commonly used method for debugging scripts is to turn on the xtrace option or to use the ksh command with the x option. These options allow an execution trace of your script. Each command from your script is displayed after variable substitution has been performed, and then the command is executed. When a line from your script is displayed, it is preceded with the value of the PS4 prompt, a plus (+) sign. The PS4 prompt can be changed.
With the verbose option turned on, or by invoking the Korn shell with the v option (ksh v scriptname), each line of the script will be displayed, just as it was typed in the script, and then executed. See Table 10.33 for debug commands.
Command | Function | How It Works |
---|---|---|
ksh x scriptname | Invokes ksh with echo option. | Displays each line of the script after variable substitution and before execution. |
ksh v scriptname | Invokes ksh with verbose option. | Displays each line of the script before execution, just as you typed it. |
ksh n scriptname | Invokes ksh with noexec option. | Interprets but does not execute commands. |
set x or | Turns on echo option. | Traces execution in a script. |
set o xtrace | ||
set +x | Turns off echo. | Turns off tracing. |
typeset ft | Turns on tracing. | Traces execution in a function. |
export PS4='$LINENO ' | The PS4 prompt by default is a +. | You can reset the prompt. In this example, a line number will be printed for each line. |
trap 'print $LINENO ' DEBUG | Prints value of $LINENO for each line in the script. | For each script command, the trap action is performed. See format for trap. |
trap 'print Bad input' ERR | If a nonzero exit status is returned, the trap is executed. | |
trap 'print Exiting from $0' EXIT | Prints message when script or function exits. |
(The Script) #!/bin/ksh # Scriptname: todebug 1 name="Joe Blow" 2 if [[ $name = [Jj]* ]] then print Hi $name fi num=1 3 while (( num < 5 )) do 4 (( num=num+1 )) done 5 print The grand total is $num (The Output) 1 $ ksh x todebug 2 + name=Joe Blow + [[ Joe Blow = [Jj]* ]] + print Hi Joe Blow Hi Joe Blow + num=1 The + is the PS4 prompt + let num < 5 + let num=num+1 + let num < 5 + let num=num+1 + let num < 5 + let num=num+1 + let num < 5 + let num=num+1 + let num < 5 + print The grand total is 5 The grand total is 5
EXPLANATION
|
(The Script) #!/bin/ksh # Scriptname: todebug2 1 trap 'print "num=$num on line $LINENO"' DEBUG num=1 while (( num < 5 )) do (( num=num+1 )) done print The grand total is $num (The Output) $ todebug2 2 num=1 on line 3 num=1 on line 4 num=2 on line 6 num=2 on line 4 num=3 on line 6 num=3 on line 4 num=4 on line 6 num=4 on line 4 num=5 on line 6 num=5 on line 4 The grand total is 5 num=5 on line 8 num=5 on line 8
EXPLANATION
|
If you are writing scripts that require a number of command line options, positional parameters are not always most efficient. For example, the UNIX ls command takes a number of command line options and arguments. (An option requires a leading dash; an argument does not.) Options can be passed to the program in several ways: ls laFi, ls i a l F, ls ia F, and so forth. If you have a script that requires arguments, positional parameters might be used to process the arguments individually, such as ls l i F. Each dash option would be stored in $1, $2, and $3, respectively. But, what if the user listed all of the options as one dash option, as in ls liF? Now the liF would all be assigned to $1 in the script. The getopts function makes it possible to process command line options and arguments in the same way they are processed by the ls program.[11] The getopts function will allow the runit program to process its arguments using a variety of combinations.
(The Command Line) 1 $ runit x n 200 filex 2 $ runit xn200 filex 3 $ runit xy 4 $ runit yx n 30 5 $ runit n250 xy filey (any other combination of these arguments )
EXPLANATION
|
Before getting into all the details of the runit program, we examine the line from the program where getopts is used to see how it processes the arguments. The following is a line from the script called runit:
while getopts :xyn: name
x, y, and n are the options.
Options typed at the command line begin with either or +.
Any options that do not contain a + or tell getopts that the option list is at an end.
The colon after an option says that the option requires an argument; that is, the n option requires an argument.
The colon before an option list says that if you type an illegal option, getopts will allow the programmer to handle it. For example, in the command runit p, where p is not one of the legal options, getopts will tell you so programmatically. The shell does not print an error message.
Each time getopts is called, it places the next option it finds, without the dash, in the variable name. (You can use any variable name here.) If there is a plus sign prepended to the option, then it goes into name with the plus sign. If an illegal argument is given, name is assigned a question mark; if a required argument is missing, name is assigned a colon.
OPTIND is a special variable that is initialized to one and is incremented each time getopts completes processing a command line argument to the number of the next argument getopts will process.
The OPTARG variable contains the value of a legal argument, or if an illegal option is given, the value of the illegal option is stored in OPTARG.
Sample getopts Scripts. The following sample scripts illustrate how getopts processes arguments.
(The Script) #!/bin/ksh # Program opts1 # Using getopts First try 1 while getopts xy options do 2 case $options in 3 x) print "you entered x as an option";; y) print "you entered y as an option";; esac done ----------------------------------------------------------------- (The Command Line) 4 $ opts1 x you entered x as an option 5 $ opts1 xy you entered x as an option you entered y as an option 6 $ opts1 y you entered y as an option 7 $ opts1 b opts1[3]: getopts: b bad option(s) 8 $ opts1 b
EXPLANATION
|
(The Script) #!/bin/ksh # Program opts2 # Using getopts Second try 1 while getopts :xy options do 2 case $options in x) print "you entered x as an option";; y) print "you entered y as an option";; 3 \?) print $OPTARG is not a valid option 1>&2;; esac done ------------------------------------------------------------------ (The Command Line) $ opts2 x you entered x as an option $ opts2 y you entered y as an option $ opts2 xy $ opts2 xy you entered x as an option you entered y as an option 4 $ opts2 g g is not a valid option 5 $ opts2 c c is not a valid option
EXPLANATION
|
(The Script) #!/bin/ksh # Program opts3 # Using getopts Third try 1 while getopts :d options do case $options in 2 d) print R " d is the ON switch";; 3 +d) print R "+d is the OFF switch";; \?) print $OPTARG is not a valid option;; esac done # Need the R option with print or the shell tries to use d as a # print option ------------------------------------------------------------------ (The Command Line) 4 $ opts3 d d is the ON switch 5 $ opts3 +d +d is the OFF switch 6 $ opts3 e e is not a valid option 7 $ opts3 e
EXPLANATION
|
(The Script) #!/bin/ksh # Program opts4 # Using getopts Fourth try 1 alias USAGE='print "usage: opts4 [-x] filename " >&2' 2 while getopts :x: arguments do case $arguments in 3 x) print "$OPTARG is the name of the argument ";; 4 :) print "Please enter an argument after the -x option" >&2 USAGE ;; 5 \?) print "$OPTARG is not a valid option." >&2 USAGE;; esac 6 print "$OPTIND" # The number of the next argument to be processed done ----------------------------------------------------------------- (The Command Line) 7 $ opts4 -x Please enter an argument after the -x option usage: opts4 [-x] filename 2 8 $ opts4 -x filex filex is the name of the argument 3 9 $ opts4 -d d is not a valid option. usage: opts4 [-x] filename 1
EXPLANATION
|
Privileged Scripts. A script is privileged if the Korn shell is invoked with the p option. When the privileged option is used and the real UID and/or the real GID are not the same as the effective UID or effective GID, the .profile will not be executed and a system file called /etc/suid_profile will be executed instead of the ENV file.
Restricted Shells. When the Korn shell is invoked with the r option, the shell is restricted. When the shell is restricted, the cd command cannot be used and the SHELL, ENV, and PATH variables cannot be modified or unset; commands cannot be executed if the first character is a backslash; and the redirection operators (>, <, |, >>) are illegal. This option cannot be unset or set with the set command. The command rksh will invoke a restricted shell.
The Korn shell has a number of built-in commands, as shown in Table 10.34.
Command | Function | |
---|---|---|
: | Do-nothing command; returns exit status zero. | |
.file | The dot command reads and executes a command from file. | |
break | See looping. | |
continue | See looping. | |
cd | Changes directory. | |
echo [ args ] | Displays arguments. | |
eval command | Shell scans the command line twice before execution. | |
exec command | Runs command in place of this shell. | |
exit [ n ] | Exit the shell with status n. | |
export [ var ] | Makes var known to subshells. | |
fc e [ editor ] [ lnr ] first last | Used to edit commands in the history list. If no editor is specified, the value of FCEDIT is used; if FCEDIT is not set, /bin/ed is used. Usually history is aliased to fc l. | |
Examples: | ||
fc l | Lists the last 16 commands on the history list. | |
fc e emacs grep | Reads the last grep command into the emacs editor. | |
fc 25 30 | Reads commands 25 through 30 into the editor specified in FCEDIT, by default the ed editor. | |
fc e | Reexecutes the last command. | |
fc e Tom=Joe 28 | Replaces Tom with Joe in history command 28. | |
fg | Brings the last background job to the foreground. | |
fg %n | Brings job number n to the foreground. Type jobs to find the correct job number. | |
jobs [ l] | Lists the active jobs by number and with the l option by PID number. | |
Examples: | ||
$ jobs | ||
[3] + Running | sleep 50& | |
[1] Stopped | vi | |
[2] Running | sleep% | |
kill [ signal process ] | Sends the signal to the PID number or job number of process. See /usr/include/sys/signal.h for a list of signals. | |
Signals: | ||
SIGHUP1 | /* hangup (disconnect) */ | |
SIGINT 2 | /* interrupt */ | |
SIGQUIT 3 | /* quit */ | |
SIGILL 4 | /* illegal instruction (not reset when caught) */ | |
SIGTRAP 5 | /* trace trap (not reset when caught) */ | |
SIGIOT 6 | /* IOT instruction */ | |
SIGABRT 6 | /* used by abort, replace SIGIOT in the future */ | |
SIGEMT 7 | /* EMT instruction */ | |
SIGFPE 8 | /* floating point exception */ | |
SIGKILL 9 | /* kill (cannot be caught or ignored) */ | |
SIGBUS 10 | /* bus error */ | |
SIGSEGV 11 | /* segmentation violation */ | |
SIGSYS 12 | /* bad argument to system call */ | |
SIGPIPE 13 | /* write on a pipe with no one to read it */ | |
SIGALRM 14 | /* alarm clock */ | |
SIGTERM 15 | /* software termination signal from kill */ | |
SIGURG 16 | /* urgent condition on I/O channel */ | |
SIGSTOP 17 | /* sendable stop signal not from tty */ | |
SIGTSTP 18 | /* stop signal from tty */ | |
SIGCONT 19 | /* continue a stopped process */ | |
(To use the kill command and a signal name, strip off the SIG prefix and precede the signal name with a dash.) | ||
Examples: | ||
kill INT %3 | ||
kill HUP 1256 | ||
kill 9 %3 | ||
kill %1 | ||
getopts | Used in shell scripts to parse command line and check for legal options. | |
hash | Lists all tracked aliases. | |
login [ username ] | ||
newgrp [ arg ] | Changes your real group ID to the group ID. | |
print [nrRsup] | Replacement for echo. See print. | |
pwd | Print present working directory. | |
read [ var ] | Read line from standard input into variable var. | |
readonly [ var ] | Make variable var readonly. Cannot be reset. | |
return [ n ] | Exit value given to a function. | |
set [ aefhknoptuvx [ o option] [ A arrayname] [ arg ] ] | ||
Examples: | ||
set | Lists all variables and their values. | |
set + | Lists all variables without their values. | |
set o | Lists all option settings. | |
set a b c | Resets positional parameters $1, $2, $3. | |
set s | Sorts $1, $2, and $3 alphabetically. | |
set o vi | Sets the vi option. | |
set xv | Turns on the xtrace and verbose options for debugging. | |
set | Unsets all positional parameters. | |
set "$x" | Sets $1 to the value of x, even if x is x. | |
set == $x | Does pathname expansion on each item in x and then sets the positional parameters to each item. | |
set A name tom dick harry | name[0] is set to tom. | |
name[1] is set to dick. | ||
name[2] is set to harry. | ||
set +A name joe | name[0] is reset to joe, the rest of the array is left alone. | |
name[1] is dick. | ||
name[2] is harry. | ||
(To set options, use the o flag; to unset options, use the +o flag.) | ||
Example: | ||
set o ignoreeof | ||
Options: | ||
allexport | After setting this, exports any variable defined or changed. | |
bgnice | Runs background jobs with a lesser priority; used instead of nice. | |
emacs | Sets the emacs built-in editor. | |
errexit | The shell exits when a command returns a nonzero exit status. | |
gmacs | Sets the built-in gmacs editor. | |
ignoreeof | Ignores the EOF (Control-D) key from terminating the shell. Must use exit to exit. | |
keyword | Adds keyword arguments occurring anywhere on the command line to the environment of the shell. | |
markdirs | Puts a trailing backslash on all directory names resulting from filename expansion. | |
monitor | Sets job control. | |
noclobber | Prevents overwriting files using the redirection operator, >. Use >| to force overwrite. | |
noexec | Same as ksh n; reads commands but does not execute them. Used to check for syntax errors in shell scripts. | |
noglob | Disables pathname expansion with ksh wildcard metacharacters. | |
nolog | Function definitions will not be stored in the history file. | |
nounset | Displays an error if a variable has not been set. | |
privileged | Turns on privileged mode for setuid programs. | |
trackall | Ksh causes each command to become a tracked alias; automatically turned on for interactive shells. | |
verbose | Echos each line of input to standard error; useful in debugging. | |
vi | Sets the vi built-in editor. | |
viraw | Specifies vi character at a time input. | |
xtrace | Expands each command and displays it in the PS4 prompt, with variables expanded. | |
shift [ n ] | Shifts positional parameters to the left n times. | |
times | Prints accumulated user and system times for processes run from this shell. | |
trap [ arg ] [ n ] | When shell receives signal n ( 0, 1, 2, or 15 ), arg is executed. | |
type [ command ] | Prints the type of command; e.g., pwd is a built-in shell. In ksh, an alias for whence v. | |
typeset [ options ] [ var ] | Sets attributes and values for shell variables and functions. | |
ulimit [ options size ] | Sets maximum limits on processes. | |
Examples: | ||
ulimit a | Display all limits: | |
Time (seconds) unlimited. | ||
File (blocks) unlimited. | ||
Data (kbytes) 524280. | ||
Stack (kbytes) 8192. | ||
Memory (kbytes) unlimited. | ||
Coredump (blocks) unlimited. | ||
Other Options: | ||
c size | Limits core dumps to size blocks. | |
d size | Limits the data size (of executables) to size blocks. | |
f size | Limits the size of files to size blocks (default). | |
m size | Limits the size of physical memory to size K bytes. | |
s size | Limits the size of the stack area to size K bytes. | |
t secs | Limits process execution time to secs seconds. | |
umask [ mask ] | Without argument, prints out file creation mask for permissions. | |
umask [ octal digits ] | User file creation mode mask for owner, group, and others. | |
unset [ name ] | Unsets value of variable or function. | |
wait [ pid#n ] | Waits for background process with PID number n and report termination status. | |
whence [ command ] | Prints information about the command, like ucb whereis. | |
Examples: | ||
whence v happy | happy is a function | |
whence v addon | addon is an undefined function | |
whence v ls | ls is a tracked alias for /bin/ls | |
whence ls | /bin/ls |
When the Korn shell is involved, it can take options to control its behavior. See Table 10.35.
Command | Function |
---|---|
a | Automatically exports all variables. |
c cmd | Executes a command string. |
e | Exits when a command returns a nonzero status. |
f | Turns off globbing, the expansion of filename metacharacters. |
h | Causes commands to be treated as tracked aliases. |
i | Sets the interactive mode. |
k | Sets the keyword option. All the key arguments to commands will be made part of the environment. |
m | Causes commands executed in the background to be run in a separate process group, and will continue to run even if Control-C or logout is attempted. Sends a message that the job has terminated when done. |
n | Can be used for debugging. Commands are scanned, but not executed. Can be used with x and v options. |
o | Allows options to be set by the names listed in the table above with the set command. |
p | Turns on privileged mode. Used for running setuid programs. |
r | Sets the restricted mode. |
s | Reads command from stdin, the default. |
t | Causes the shell to exit after executing the first command found in shell input and the c option is specified. |
u | Any reference to an unset variable is considered an error. |
v | Each line of a script or standard input is printed before any parsing, variable substitution, or other processing is performed. Output is written to standard error. Used for debugging. |
x | Each line of a script or standard input is printed before it is executed. Filename expansion, variable substitution, and command substitution are shown in the output. All output is prepended with the value of the PS4 prompt, a plus sign followed by a space. Lines are written to standard error. |
1: | What shell are you using? How do you know? |
2: | Do you have a .profile and/or a .kshrc file in your home directory? What is the difference between the .profile and .kshrc? What is the ENV file and how can you invoke it if you make changes in it? |
3: | What is the default primary prompt? What is the default secondary prompt? Change your primary prompt at the command line so that it contains your login name. |
4: | What is the purpose of setting each of the following variables?
Why are these variables set in the ENV file? What is the purpose of the PATH? What are the elements of your PATH variable? |
5: | What is the difference between a local and an environment variable? How do you list all your variables? How do you list only environment variables? To list all your current option settings, type the following: set o Which set options are turned on? |
6: | Create a local variable called myname that contains your full name. Now export the variable. Type the following at the prompt: ksh Was the variable name exported? Type exit to get back to the parent shell. Make the variable name readonly. What is a readonly variable? |
7: | What are positional parameters normally used for? Type the following: set apples pears peaches plums Using the positional parameters, print plums. Print apples peaches. Print apples pears peaches plums. Print the number of parameters. Reset the positional parameters to a list of veggies. Print the whole list of veggies. What happened to the fruit list? Type the following: set print $* What happened? |
8: | Print the PID of the current shell. Type the following at the prompt: grep $LOGNAME /etc/passwd echo $? What does the $? tell you. What does the exit status tell you about the execution of a command? |
9: | Change both the primary and secondary prompt in your .profile. How do you reexecute the .profile file without logging out and logging back in? |
1: | What is your HISTSIZE variable set to? What is your HISTFILE variable set to? Check your .kshrc file to see if set o vi is there. If it has not been set, set it in the .kshrc file and reexecute the file by typing the following: . .kshrc |
2: | Type the following commands at the command line: ls date who cal 2 1993 date +%T Type history or fc l. What do these commands do? Print your history list in reverse. Print your history list without numbers. Print the current command and the five preceding it. Print everything from the tenth command to the present. Print everything between the most recent ls command to the most recent cal command. |
3: | Using the r command, reexecute the last command. Reexecute the last command that started with the letter d. Change the cal command year output to 1897. Change the date command +%T argument to find the current hour. |
4: | If your history is set, press the Esc key at the command line and use the K key to move up through the history list. Change the ls command to ls alF and reexecute it. |
5: | Check to see if the FCEDIT variable has been set by typing the env command. If it has not been set, type the following at the command line: export FCEDIT=vi Now type the following at the command line: fc 1 4 What happened? |
6: | How do you comment a line from your history list, so that it will be placed on the list without being executed? |
7: | At the command line, type the following: touch a1 a2 a3 apples bears balloons a4 a45 Now using the history Esc sequences shown in Tables 10.2 and 10.3, print all the files beginning with an a.
|
8: | At the command line, type the following: print a b c d e |
9: | Using the history Esc underscore command, change the command to the following: print e Using the history Esc underscore command, change the first command to output: print c |
1: | What command lists all the aliases currently set? |
2: | What command lists all the tracked aliases? |
3: | Create aliases for the following commands:
|
4: | How do you export an alias? |
5: | Create a function that contains the following commands:
|
6: | Execute the function. |
7: | Now create your own functions, using positional parameters to pass arguments. |
8: | What command lists the functions and their definitions? |
9: | Try some of the print options. |
1: | Create a directory called meta. Cd to that directory. Use touch to create the following files: abc abc1 abc2 abc2191 Abc1 ab2 ab3 ab345 abc29 abc9 abc91 abc21xyz abc2121 noone nobody nothing nowhere |
2: | Do the following:
|
1: | Use the tilde to do the following:
|
2: | What variable holds the value of your present working directory? What variable holds the value of your previous working directory? |
3: | Use the to go to your previous working directory. |
4: | Use the print command to send the following output to the screen. (The word enclosed in < > is a variable name that will be expanded, and words enclosed in [ ] are output of commands that have been executed; i.e., use command substitution.) Hi <LOGNAME> how's your day going? "No, <LOGNAME> you can't use the car tonight!", she cried. The time is [ Sun Feb 21 13:19:27 PST 2001 ] The name of this machine is [ eagle ] and the time is [ 31:19:27 ] |
5: | Create a file that contains a list of user names. Now create a variable called nlist which contains the list of user names, extracted by using command substitution.
|
1: | Go into the editor and create the following two-line text file called ex6: Last time I went to the beach I found a sea shell. While in Kansas I found a corn shell. |
2: | Now append this line to your ex6 file: The National Enquirer says someone gave birth to a shell, called the born shell. |
3: | Mail the ex6 file to yourself. |
4: | Using a pipe, count the number of lines (wc l) in your ex6 file. |
5: | To list all set options, type the following: set o Do you have the noclobber variable set? If not, type the following: set o noclobber What happened? |
6: | Type the following at the command line: cat << FINIS How are you $LOGNAME The time is 'date'Bye!! FINIS What printed? |
7: | Now try this using tabs: cat << END hello there how are you END What printed? |
8: | Type the following at the command line: kat file 2> error || print kat failed What happened? Why? |
9: | Now type the following at the command line: cat zombie 2> errorfile || print cat failed What happened? Why? How does the && operator work? Try your own command to test it. |
10: | Use the find command to print all files that begin with an a from the root directory down. Put the standard output in a file called foundit and send the errors to /dev/null. |
1: | At the command line type the following: mail <user>Press control z Now type: jobs What is the number in the square brackets? |
2: | Now type: sleep 300 jobs bg What does bg do? What do the + and signs indicate? |
3: | Kill the mail job using job control. |
4: | Go into the editor. Type ^Z to stop the job. Now bring the stopped vi job back into the foreground. What command did you type? |
5: | Type the following command: jobs l What is the output? |
6: | What is the TMOUT variable used for? |
7: | How much time was spent by the kernel when executing the following command: (sleep 5 ; ps eaf ) |
1: | Write a program called info. Make sure you make the program executable with the chmod command before you try to execute it. |
2: | The program should contain comments. |
3: | The program should do the following when executed:
|
1: | Write a script that will do the following:
|
1: | Create a file called datafile if it has not been provided for you on the CD. It will consist of colon-separated fields:
|
2: | Put 10 entries in your file. Write a script called lookup that will do the following:
|
1: | Write a script that will do the following:
|
2: | Use the typeset command to convert the first and last name variables to all lowercase letters. |
3: | Test to see if the person's name is tom jones. If it is, print Welcome, Tom Jones; if it is not, print, Are you happy today, FIRSTNAME LASTNAME?. (The user's first and last names are converted to uppercase letters.) |
4: | Have the user type in an answer to the question and use the new ksh test command to see whether the answer is yes or no. If yes, have your script say something nice to him or her, and if no, tell the user to go home and give the current time of day. |
5: | Rewrite the lookup script.
A variable for each item will be assigned the user input. print n "What is the name of the person you are adding to the file?" read name The information will be appended to the datafile. |
1: | Write a script called grades that will ask the user for his or her numeric grade on a test.
|
2: | Write a script called calc that will perform the functions of a simple calculator. The script will provide a simple menu:
|
3: | The user will choose one of the letters from the menu. |
4: | The user will then be asked to enter two integers between 0 and 100. |
5: | If the numbers are out of the range, an error message will be printed and the script will exit. |
6: | The program will perform the arithmetic on the two integers. |
7: | The answer will be printed in base 10, 8, and 16. |
1: | Write a script timegreet that will do the following:
|
2: | Rewrite the lookup script, replacing the if/elif construct with the case command. Add one more menu item:
|
1: | Write a script that will do the following:
|
2: | Rewrite the lookup script using the select command to create a main menu and a sub menu. The menu will resemble the following: 1) Add Entry 2) Delete Entry 3) Update Entry 4) View Entry a) Name b) Phone c) Address d) Birthday e) Salary 5) Exit |
Steps for autoloading a function:
1: | Make a directory called myfunctions. |
2: | Change directory to myfunctions and use the editor to create a file called goodbye. |
3: | Insert in the goodbye file a function called goodbye, spelled exactly the same as the filename. |
4: | The goodbye function contains: function goodbye { print The current time is $(date) print "The name of this script is $0" print See you later $1 print Your machine is 'uname n' } |
5: | Write and quit the editor. You now have a file containing a function with the same name. |
6: | Go to your home directory. Modify the .kshrc file in the editor by typing the following line: FPATH=$HOME/myfunctions |
7: | Exit the editor, and to execute the .kshrc in the current environment, use the dot command. |
8: | In the timegreet script you have already written, include the following lines: autoload goodbye goodbye $LOGNAME |
9: | Run the timegreet script. The goodbye function output will appear. |
10: | Create functions for each of the menu items in the lookup script. Store the functions in a file called lookup_functions in a directory called myfunctions. |
11: | Autoload the functions in your lookup script and make the function calls for the corresponding cases. |
12: | Use the trap command so that if the user enters a menu selection other than an integer value, the trap command will print an error to the screen, and cause the script to ask the user to reenter the correct data type. |
[1] A built-in command will override a function; therefore, an alias must be defined to the name of the function. (See "Aliases".) In the 1994 version of the Korn shell, the order of processing functions and built-ins was reversed, thus alleviating this problem.
[2] On versions of the Korn shell newer than 1988, the FCEDIT variable has been renamed HISTEDIT, and the fc command has been renamed hist.
[3] Tracked aliases will be undefined if the PATH variable is reset.
[4] Using backquotes for command substitution is an old form still used in the Bourne and C shells. Although still legal syntax, the Korn shell introduces a new method shown in this section.
[5] The POSIX standard defines functions with the Bourne shell syntax, but variables and traps cannot be local in scope, as with the new Korn shell definition.
[6] Bases greater than 36 are available on versions of the Korn shell that are newer than 1988.
[7] If you want the menu to reappear when the loop starts again, set the REPLY variable to null just before the done keyword.
[8] Korn, David G., and Bolsky, Morris I., The Korn Shell Command and Programming Language (Englewood Cliffs, NJ: Prentice-Hall, Inc., 1988), p. 77.
[9] Bolsky, Morris, and Korn, David, The New Kornshell. (Upper Saddle River, NJ: Prentice Hall, 1995), p. 78.
[10] Bolsky, Morris I., and Korn, David G., The New KornShell Command and Programming Language (Englewood Cliffs, NJ: Prentice Hall PTR, 1995), p. 327.
[11] See Section 3 of the UNIX manual for the C library function getopt.
CONTENTS |