Mac OS X Unleashed

Mac OS X Unleashed

By John Ray and William C. Ray

Customizing Your Shell Environment and Storing Data

Variables are a way of addressing bits of the computer memory so that we can store random pieces of information in it. It would be difficult to do much productive work with a computer if all we could store in any location was one particular, predetermined piece of information. Variables give us the ability to name a region X, and store whatever value we want in X, and change the value whenever we want. Variables in the shell are used both to hold data to be used in commands and programs written in the shell, and to control the behavior of certain aspects of the shell. You've already been introduced peripherally to this second use by way of the path variable, which affects where the shell looks to find executable programs. We'll go into somewhat more detail on this use in the next section, and cover the former later in this chapter.

Environment and Shell Variables

Many shells make a distinction between environment variables and shell variables in one way or another. Both are variables that you can set and use in a shell. The difference is that environment variables are inherited by any programs (such as subshells) that are children of (Unixism for "run by") that shell, whereas shell variables are not inherited. This might not seem a useful distinction, but there are significant uses for each type. Noninherited shell variables don't cost memory and startup time for subshells, and can be expected to be empty in any shell until they are used to store something. Inherited environment variables, on the other hand, must be copied into the memory space of child programs, taking room and time, and they can be used to pass information between a parent shell and programs that it executes.

Setting shell and environment variables is similar in tcsh, although there are a few syntactic differences between the way that they're used in some situations. To set a shell variable, the syntax is as follows:

set <shellvariablename> = <value>

To set a shell variable named x to contain the value 7, the shell expression is simply

set x=7

To set an environment variable to a particular value, the syntax is

setenv <environmentvariablename> 
   <value>

To set an environment variable named Y to contain the value 8, the shell expression is

setenv Y 7

Both shell and environment variables are addressed for use by the prepending of a $ sign before the variable names. A simple demonstration can be accomplished with the echo command, which prints to the STDOUT of the shell, the value of the expression following it.

localhost ray 200> echo "Hi There"

     Hi there

localhost ray 201> echo $x

     x: Undefined variable.

localhost ray 202> set x=7
localhost ray 203> echo $x
     7

localhost ray 205> setenv Y 8
localhost ray 206> echo $y

     y: Undefined variable.

localhost ray 207> echo $Y

     8

localhost ray 208> @ z = ( $x + $Y )
localhost ray 209> echo $z

     15

Here, a shell variable x and an environment variable Y have been set to values 7 and 8, respectively, and their values have been printed to the terminal. The @ command is a tcsh shell built-in command, similar to the set command. However, the set command treats all its arguments as strings, whereas the @ command treats them as numbers, allowing math operations such as +, -, /, and *. The @ command, like the set command, sets a shell variable (or creates it if it does not exist). The set and @ commands can also be used as [set or @] <variablename> [ n ] = <expression> . In this form, the command attempts to treat the variable <variablename> as an array, and set item n (the n th word, if echoed) to the value of <expression> . Table 18.1 lists the most frequently used methods for setting variable values. (Frankly, the need for a separate command to operate on variables as numeric values, rather than string values, is one of the most annoying weaknesses of the csh/tcsh shell model.)

Table 18.1. tcsh Syntax Options for Setting Shell and Environment Variables to Values

Expression syntax Effect
<word> Used as a part of a command-line expression, <word> is a string of non-whitespace characters, or a quoted string that possibly contains spaces.
$ <variable> Expands to the contents of <variable> . This will typically be a <word> or <wordlist> . $ <variablename> preferentially expands to the value of the shell variable by the name <variablename> , if both shell and environment variables with this name exist.
set <variable> = <word> Sets the value of <variable> to <word> .
set <variable> [ n ] = <word> Treats <variable> as an array of words, and sets the n th value to <word> . This has the effect of setting the n th word of a wordlist to <word> .
setenv <variable> <word> Sets the environment variable <variable> to contain the value <word> . Most variable manipulations must be done in shell variables, and the values transferred into environment variables if needed.
@ <variable> = <expre s sion> Treats <expression> as a mathematical expression, attempts to evaluate it, and assigns the result to <variable> . Most forms of errors in attempts at this result in the response @: Expression Syntax .
@ <variable> = ( <expre s sion> ) Same as the previous item. Parentheses can be used to order the execution of parts of the expression, and it's frequently helpful to use them around any expression on general principles.
@ <variable> [ n ] = <expre s sion> Treats <variable> as an array, and sets the n th value of it to the value of <expression> .

To demonstrate the difference between shell and environment variables, you can create a subshell and test the variables you used in the previous example in it:

localhost ray 210> tcsh

     /Users/ray
localhost ray 151> echo $x

     x: Undefined variable.

localhost ray 152> echo $Y

     8

As you can see, after the subshell is started (notice that the command number in the prompt drops to 151—the size of my retained command history list), the environment variable Y maintains its value and the shell value x becomes undefined.

As mentioned earlier, certain shell and environment variables affect the behavior of some parts of the shell, or of programs that run as children of the shell. Table 18.2 lists the tcsh shell variables that affect the behavior of tcsh and a few intimately related programs. Please remember that any program you run in a shell may be additionally affected by environment variables. For example, the man command determines where to look for man pages by examining the MANPATH environment variable. If you set this environment variable to some path in your shell, the man command will inherit it and search in that path for man pages. Because every program may independently choose to examine any environment variables it chooses, it's best to look at the man pages for any programs to determine whether there are environment variables with which you can affect the program's behavior.

Table 18.2. The tcsh Reserved Shell Variables

Shell Variable Effects
addsuffix Controls addition of / to the end of directories paths, and spaces after normal filenames when expanded by shell filename autocompletion.
afsuser If set, the username to autologout under kerberos authentication.
ampm If set, shows time in 12-hour AM/PM format.
argv The list of arguments passed to the shell on startup.
autocorrect If set, attempts to fix command misspellings.
autoexpand If set, passes command completion attempts through the expand-history processor. (See the tcsh man page for more details.)
autolist If set, lists possible expansions for autocompletion, if the expansion is ambiguous. If the value is set to ambiguous, lists possibilities only when an autocompletion attempt does not add any new characters.
autologout The number of minutes of inactivity before autologout. Optionally, the number of minutes before automatic locking of the terminal.
backslash_quote If set, backslashes (\ characters) are automatically inserted before any backslash or quote character in a command completion.
cdpath A list of directories in which cd should look for subdirectories if they aren't in the current working directory.
color If set, enables color display for the ls command and shell built-in command ls-F.
command If set, contains the command which was passed to the shell with a -c flag.
complete If set to enhance, completion ignores filename case, considers periods, hyphens, and underscores to be word separators, and hyphens and underscores to be equivalent.
correct If set to cmd, attempts automatic spelling correction for commands. If set to complete, commands are automatically completed. If set to all, the entire command line is corrected.
cwd The full path of the current working directory.
dextract If set, pushd + n extracts the n th subdirectory from the stack, rather than rotating it to the top.
dirsfile The default location in which dirs -S and dirs -L look for their history.
dirstack An array of all directories in the directory stack.
dspmbyte If set to euc, enables display and editing of EUC-Kanji (Japanese) code. If set to sjis, enables display and editing of Shift-JIS (Japanese) code. Other options are available—see the tcsh man page for more details.
dunique If set, pushd removes any instances of the pushed directory from the stack, before pushing it onto the top of the stack.
echo If set, each command and its arguments are echoed to the terminal before being executed.
echo_style The style of the echo built-in. May be set to bsd, sysv, both, or none to control the behavior of the echo command. See the tcsh man page for more details on behavior affected.
edit If set, allow command-line editing.
ellipsis If set, use an ellipsis to represent portions of the path that won't fit in the prompt.
fignore List of filename suffixes to be ignored in completion attempts.
filec An unused tcsh shell variable, included to maintain backward compatibility with csh, which used this variable to control whether completion should be used.
gid The user owning the shell's real group ID.
group The user owning the shell's group name.
histchars A string determining the characters used in history substitution. The first character replaces the default ! character, and the second replaces the default ^ character.
histdup Controls handling of duplicate entries in the history list. If set to all, only unique history events are entered into the history. If set to prev, a run of identical commands is reduced to a single entry in the history list. If set to erase, a repeat of a command already in the history list removes the previous occurrence from the history.
histfile The default location in which history -S and history -L look for a history file. If unset, ~/.history is used.
histlit If set, the shell built-in, editor commands, and history-saving mechanism use the literal (unexpanded) form of lines in the history list.
history The first word indicates the number of history events to save. The optional second word indicates a format for printing the history. See the tcsh man page for more details on format control strings.
home Initialized to the home directory of the user. Command-line expansion of ~ refers to this variable for its action.
ignoreeof If set to the empty string or 0 and the input is a terminal, an end-of-file command sent to the terminal causes the shell to print an error, rather than exit.
implicitcd If set, the shell treats a directory name entered on the command line as though it were entered as the argument of a cd command.
inputmode Can be set to insert or overwrite to control the behavior of command-line editing.
listflags Contains command-line flags to include with any used when issuing the ls-F shell built-in.
listjobs If set, all current jobs are listed when a running job is suspended.
listlinks If set, the ls-F shell built-in command shows the time of file to which symbolic links point.
listmax The maximum number of items that the list-choices command-line editor and autocompletion will list, without prompting.
loginsh Set by the shell if it is a login shell.
logout Set by the shell to normal before a normal logout, automatic before an automatic logout, and hangup if the shell was killed by a hangup signal (typically generated by kill-HUP, or by a terminal connection being interrupted, rather than cleanly exited).
mail The name of the files or directories to check for incoming mail. See both the tcsh and mail man pages for more information on the behaviors controlled by this variable.
matchbeep Controls whether and when command-line completion rings the bell. Setting it to never prevents all beeps. nomatch beeps when there is no current match. ambiguous beeps when there are multiple matches. notunique beeps when there is an exact match, as well as other longer matches. If unset, the behavior is the same as ambiguous.
nobeep If set, beeping is completely disabled.
noclobber If set, the shell attempts to prevent output redirection from overwriting existing files. See the tcsh man page for more details.
noglob If set, filename substitution and directory substitution are inhibited. Normally used only as a performance enhancement for shell scripts where filenames are already known.
nokanji If set, disables kanji support, so that the meta key is used.
nonomatch If set, a filename or directory substitution that doesn't match any files does not cause an error.
nostat A list of directories, or patterns that match directories, that should not be examined for matches during completion attempts.
notify If set, announces job completions immediately, rather than waiting until just before the next command prompt appears.
owd The previous working directory.
path A list of directories in which to look for executable commands. The path shell variable is set at startup from the PATH environment variable.
printexitvalue If set and a program exits with a non-zero status, prints the status.
prompt The string that is printed as the prompt for command-line input. This can contain both literal strings for display as well as a number of special patterns indicating the substitution of everything from the current directory, to the user name. See the tcsh man page for the (rather extensive) list of options available.
prompt2 The string to use for the inner prompt in while and foreach loops. The same format sequences as used in the prompt variable may be used in prompt2.
prompt3 The string to use for prompting regarding automatic spelling corrections. The same format sequences as used in the prompt variable may be used in prompt2.
promptchars If set, specifies a pair of characters to substitute between for a shell prompt when a normal user, and when su-ed to the super user.
pushdtohome If set, pushd without any arguments is equivalent to pushd ~.
pushdsilent If set, pushd and popd don't print the directory stack.
recexact If set, completion is finished with an exact match, even if a longer one is available.
reco g nize_only_executables If set, command listings display only files in the path that are executable.
rmstar If set, the user is prompted before rm * is allowed to execute.
rprompt The string to print on the right-hand side of the screen when the prompt is displayed on the left. This prompt accepts the same formatting controls as the prompt variable. In your author's opinion, this is a bizarre shell capability.
savedires If set, the shell does a dirs -S before exiting.
savehist If set, the shell does a history -S before exiting.
sched The format in which the sched built-in prints scheduled events. The string format is the same as that for prompt.
shell The file in which the executable shell resides.
shlvl The nested depth of the current shell beneath the login shell for this session.
status The status returned by the last command to exit.
symlinks Can be set to several different values to control the resolution of symbolic links. See the tcsh man page for more details.
tcsh The version number of the tcsh shell.
term The terminal type currently being used to work in the shell.
time If set to a number, execute the time built-in after any command that takes longer than that number of seconds. Can also control the format of the output of the time commands so executed. See the tcsh man page for further information.
tperiod The period, in minutes, between executions of the tcsh special alias, periodic.
tty The name of the tty for the current terminal, or empty if the current shell is not attached to a terminal.
uid The user's real numeric user ID.
user The user's login name.
verbose If set, causes the words of each command to be printed after any history substitution. Can be set on startup by executing the shell with the -v command.
version The shell's version ID stamp, as well as a considerable amount of information regarding compile-time options that were specified when the shell was compiled. See the tcsh man page for more information on interpreting the output.
visiblebell If set, flash the screen, instead of using an audible terminal bell.
watch A list of user/terminal pairs to watch for logins and logouts.
who The format string for watch messages. See the tcsh man page for specific format information.
wordchars A list of nonalphanumeric characters to be considered part of a word by the command-line editor.

Shell and environment variables can also be addressed in a number of ways other than with the simple $ <variablename> method used to return the contents of the variable. Table 18.3 lists available alternatives for accessing other information in the shell or other information regarding the variable, such as the number of words in the variable or whether the variable actually has a value.

Table 18.3. Alternative Variable Addressing Methods

Addressing a Variable As Returns
$name  
${name} The value of the variable.
  If the variable contains multiple words, each is separated by a blank. The braces insulate name from characters following it.
$name[selector]  
${name[selector]} Treats name as an array of words, and returns only the selected element from the list of words.
$0 Substitutes the name of the file from which command input is being read (used in shell scripts).
$number  
${number} Equivalent to $argv[number]. Remember that argv is the array of command-line arguments passed to the shell.
$* Equivalent to $argv.
$?name  
${?name} Substitutes 1, if variable name is set, 0, if it is not.
$?0 Substitutes 1 if the name of the program running the shell is known. This is specifically applicable to shell scripts, and is always 0 for interactive shells.
$#name  
${#name} Substitutes the number of words in name.
$# Equivalent to $#argv.
$%name  
${%name} Substitutes the number of characters in name.
$? Equivalent to $status.
$$ Substitutes the process number of the parent shell.
$! Substitutes the process number of the most recent background process started by the shell.
$< Substitutes a line from STDIN. This can be used to read input from the keyboard into a shell script.

Variable Substitution Modifiers

Along with the capability to set variables to specific values, and to manipulate variable values by the use of external programs, the shell also contains some capability to modify variables internally as well. This capability is mainly targeted to modification of command, filename, and path-like contents in variables. For example, this allows you to parse the extension part of a filename off a file with a name like myfile.jpg—keeping either the extension, jpg, or the main name, myfile. These manipulations are effected by appending to the variable one or more sets of a colon followed by a modifier string. Table 18.4 shows the allowable substitution modifier strings.

Table 18.4. Shell and Environment Variable Substitution :<modifier> Options

Modifier String Effect
h Removes a trailing pathname component, leaving the head.
t Removes all leading path components, leaving only the trailing file component.
r Removes a filename extension .xxx, leaving the head portion of the filename before this.
e Removes everything from a filename except for the extension.
u Changes the case of the first lowercase letter to uppercase.
l Changes the case of the first uppercase letter to lowercase.
s/l/r/ Substitutes l for r. l can be any simple string, as can r.
g Applies the next modifier to each word, rather than just to the first.
a Applies the next modifier as many times as possible to a single word. Beware of creating modification loops with this option.

As a simple example, if the variable x contains /home/ray/testfile.jpg, we can extract and act upon several different parts of this variable by using the modifiers shown in Table 18.4.

localhost ray 152> set x=/home/ray/testfile.jpg
localhost ray 153> echo $x

     /home/ray/testfile.jpg

localhost ray 154> echo $x:h

     /home/ray

localhost ray 155> echo $x:t

     testfile.jpg

localhost ray 156> echo $x:r

     /home/ray/testfile

localhost ray 157> echo $x:e

     jpg

localhost ray 158> echo $x:u

     /Home/ray/testfile.jpg
localhost ray 159> echo $x:s/test/special/

     /home/ray/specialfile.jpg

localhost ray 171> set y=( /home/ray/testfile.jpg /home/ray/filetest.jpg )
localhost ray 172> echo $y

     /home/ray/testfile.jpg /home/ray/filetest.jpg

localhost ray 173> echo $y:u

     /Home/ray/testfile.jpg /home/ray/filetest.jpg

localhost ray 174> echo $y:gu

     /Home/ray/testfile.jpg /Home/ray/filetest.jpg

localhost ray 175> echo $y:au

     /HOME/RAY/TESTFILE.JPG /home/ray/filetest.jpg

Command History Substitution

As briefly mentioned earlier, the tcsh shell, as well as some others, maintains a history of commands that you have executed at the command line. Although we've mentioned only selecting previous commands out of the history by use of the arrow keys up to this point, the shell actually provides a number of options for the use of previous commands from the history in more sophisticated ways. Primary among these is the ability to select among the previous commands, and substitute new information for previous information in the commands. The modification strings for variables detailed earlier can be applied to commands in the history, and some additional history-specific modifiers can be used as well. The basic form of history substitution is simply the exclamation point, which indicates that a history substitution is to take place at that point in the command line. The characters following the exclamation point specify which item from the history is to be used and, optionally, what modifications need to be made to it. Table 18.5 lists the history item specifiers that can follow the exclamation point history substitution indicator.

Table 18.5. History Substitution Options

Item Following ! Character Meaning to the History Mechanism
n ( n is a number) Execute the item with that number out of the history list.
- n ( n is a number preceded by a minus sign) Execute the command n items before the current one.
# (the pound sign) The current command. This allows recursion, so be careful! To indicate a modification of the current event, the # sign indicating the current command can be omitted if there is a substitution modifier used also.
! The previous command (equivalent to -1).
s ( s is a character) Execute the most recent command whose first word begins with s .
?s? ( s is a string) The most recent event that contains the string s .

For example, a user's command history (listable by use of the history command) is shown in part here:

localhost ray 191> history | tail -5

        186  21:34   ls -l
        187  21:37   cp file1.ps file1.ps.bak
        188  21:37   cp /usr/test/storage/file1.ps ./
        189  21:37   lpr file1.ps
      190  21:38   history | tail -5

We could execute another lpr file1.ps simply by typing !l on a command line. Alternatively, !?ora? would execute the copy from /usr/test/storage by matching the string ora from storage. !! would re-execute the history command, and !-4 would execute the copy to file1.ps.bak again, as would !187 These are shown here:

localhost ray 192> !l

     lpr file1.ps

Localhost ray 193> !?ora?

     cp /usr/test/storage/file1.ps ./

localhost ray 194> !!

     history | tail

localhost ray 195> !-4

     cp file1.ps file1.ps.bak

localhost ray 196> !187

     cp file1.ps file1.ps.bak

These commands can be combined with substitution modifiers for variables as detailed earlier to further reduce the amount of typing effort needed:

localhost ray 201> !?ora?:s/1/2/

     cp /usr/test/storage/file2.ps ./

localhost ray 202> !187:gs/1/2

     cp file2.ps file2.ps.bak

localhost ray 203> !187:r.newbak

     cp file1.ps file1.ps.bak.newbak

Table 18.6 shows some history-specific : <modifier> strings that can be applied to history substitutions.

Table 18.6. History-Specific :<modifier> Options

Modifier String Action
& Repeat the previous substitution in this position.
p Print out a history substitution with expanded substitutions, rather than execute the command.
q Quote the value after this modification, preventing further modifications.
0 The leftmost argument of the command (typically, the command itself).
n The n th argument of the command.
^ The first argument, equivalent to 1. The colon can be omitted from before this modifier.
$ The last argument. The colon can be omitted from before this modifier.
% The word matched by an ? s ? search. The colon can be omitted from before this modifier.
x - y A range of arguments from the x th to the y th.
- y Equivalent to 0- y . The colon can be omitted from before this modifier.
* Equivalent to ^-$, but returns nothing if the command is the only argument. The colon can be omitted from before this modifier.
x* Equivalent to x-$.
x- Equivalent to x*, but omits the last word $.

Aliases

The alias command is a simple tool that can help you customize your environment. It is the textual equivalent of the graphical Mac OS icon aliases (or Windows shortcuts) that you're probably already familiar with. It lets you specify a new name by which you can refer to an existing command. If you don't like typing history to list your command history, you can use the alias command to make typing h equivalent to typing history. We could have introduced this command much earlier in the discussion, but the information you have just learned about history and variable substitution makes the alias command much more powerful. The alias command has an almost trivial syntax: alias <newname> <definition> . It accepts no command-line options, and has no arguments or flags to control it. To alias h, so that it calls history as described earlier, is simply alias h history.

The real power of the alias command, however, comes from the ability to use history substitutions in the <definition> part of the alias. For example, there are a number of machines in another domain that I access on a regular basis. It's inconvenient to have to type slogin oak.cis.ohio-state.edu, and slogin shoe.cis.ohio-state.edu, and so on whenever I need to access one of these machines. Using the trivial application of alias, I could change slogin so that I could type something shorter, such as scis. This would still leave me typing scis oak.cis.ohio-state.edu, and so on. Using the history substitution capability, however, this can be made much more useful. In this case, I can use the * modifier to the history, executed against the current command in the history (#), to pass the arguments given to my alias to another command of my choice. Specifically, what I've done is alias scis 'slogin \ !#:*.cis.ohio-state.edu'. The backslash before the history expansion prevents it from being expanded immediately at the prompt when I entered the alias command. Now, all I have to do is type scis oak, and the alias command expands the command to slogin !#:*.cis.ohio-state.edu. The history substitution then replaces the !#:* with the argument given to the command, which in this case is oak. The final command executed is slogin oak.cis.ohio-state.edu.

This might seem complicated, but a simple demonstration should suffice to make it clearer.

localhost ray 156> h

     h: Command not found.

localhost ray 157> alias h history
localhost ray 158> h | tail -3

        156  23:56   h
        157  23:56   alias h history
      158  23:56   h | tail -5

localhost ray 159> scis

     OK? sccs oak? no
     scis: Command not found. 

localhost ray 160> alias scis 'slogin \!#:*.cis.ohio-state.edu'
localhost ray 161> scis oak

     ray@oak.cis.ohio-state.edu's password:

To remove an alias, simply use the unalias command on the <newname> that you've created for your command.

Share ThisShare This

Informit Network