CONTENTS |
Most UNIX variants allow you to select among several shells. The shell is important to you as a user because it is your window into the system. The many shells available on UNIX variants are similar in that you use them to issue commands, control many aspects of your user environment, write command files and shell programs, and so on. Because you'll probably be spending a lot of time in your shell, you should develop an understanding of several different shells and see if you develop a preference for one over the other. A particular shell, such as Bash, does not vary much from one UNIX variant to another. The shells themselves, however, have some unique features. In general, I don't find that users strongly prefer one shell over another. All the shells are similar in functionality and are enjoyable to use once you get to know them. Most UNIX variants allow your system administrator to select from among several different shells when configuring users, so there is usually some flexibility concerning the shell that users run. In general, system administrators prefer users to use the same shell, making system administration easier in general. Most system administrators, however, are happy to grant a user request for a particular shell if indeed it is available on your system and you have a good reason to use it. I'll cover the C shell in this chapter. Bash and KornShell were covered in the two previous chapters.
The C shell is similar to other shells in that it provides a user interface to UNIX. You can use the C shell in the following three ways:
Interactively type commands on the command line.
Group commonly executed sets of commands into command files that you can execute by typing the name of the file.
Create C shell programs using the structured programming techniques of the C shell.
These three techniques are listed in the order in which you'll probably use them. First, you log in and use interactive commands. Then you group together commonly used commands and execute them with a single command. Finally, you may want to create sophisticated shell scripts.
In this chapter, I cover login and interactive commands and a lot of useful ways to use the C shell.
Most of the examples in this chapter are from Solaris and HP-UX systems. You probably will find both your user setup and the operation of the C shell on other systems similar to what is covered in this chapter. Much of the setup of any shell is performed by the system administrator, so you will surely find differences in your C shell setup compared with what is shown in this chapter. In general, however, the operation of the C shell is similar from one system to another.
The first activity you perform after you log into the system is to issue commands at the prompt. A command you may want to issue immediately is ls -al. Hereis what I see on my system afterexecuting this:
sys1 7: ls -al total 10 drwxr-x--- 2 martyp2 users 96 May 5 09:34 . drwxr-xr-x 10 root root 1024 May 5 10:38 .. -rw-r--r-- 1 martyp2 users 814 May 5 09:34 .cshrc -rw-r--r-- 1 martyp2 users 347 May 5 09:34 .exrc -rw-r--r-- 1 martyp2 users 341 May 5 09:34 .login -rw-r--r-- 1 martyp2 users 446 May 5 09:34 .profile sys1 8:
The C shell prompt consists of system name (sys1) followed by the command number and a colon. I cover the prompt shortly.
ls -al shows two files related to the C shell in this user area:
.cshrc and.login
Figure 11-1 is the contents of.cshrc.
Figure 11-2 shows the contents of.login.
The sequence of events after login varies from one UNIX system to another. On many systems, the.cshrc is first read and executed by the C shell. You can modify the.cshrc file to specify the command-line prompt you wish to use, initialize the history list, and define aliases. The upcoming sections describe the way the.cshrc fileshown in Figure 11-1 defines these. Let's first take a quick look at the .login file in the next section.
On many UNIX systems the.login file is read after the.cshrc file. There are only two issues related to setup present in the example shown. The first is the tset command, which sets the TERM environment variable. The eval preceding tset means that the C shell executes tset and its arguments without creating a child process. This allows tset to set environment variables in the current shell instead of a subshell, which would be useless. The stty command is used to set terminal I/O options. The two set commands are used to define shell variables, which I will describe shortly. The noclobber does not permit redirection to write over an existing file. If you try to write over an existing file, such as /tmp/processes below, you receive a message that the file exists:
sys1 1: ps -ef > /tmp/processes /tmp/processes: File exists
The ">" means to take the output of ps and rather than write it to your screen, write it to /tmp/processes. The file /tmp/processes will not be written over, however, with the output of ps -ef because /tmp/ processes already exists and an environment variable called noclobber has been set. If noclobber is set, then redirecting output to this file will not take place. This is a useful technique for preventing existing files from being accidently overwritten. There are many forms of redirection that you'll find useful. Redirection is covered later in this chapter.
The C shell can keep a history list of the commands you have issued. If you wish to reissue a command or view a command you earlier issued, you can use the history list.
The commands issued are referred to by number, so you want to have a number appear at the command prompt. The following line in.cshrc provides a number following the system name:
set prompt = "$system \!: " sys1 1:
We will nget into shell and environment variables shortly, but for now it is sufficient to know that $system corresponds to system name "sys1."
You can specify the number of previously issued commands you want to save and view when you issue the history command. The following line in.cshrc sets the history list to 20:
set history = 20
The last 20 commands issued are displayed when you issue the history command.
The savehist variable allows you to save a specified number of history commands after logout. By default, when you log out, the history list is cleared. This variable has a value of 20, so upon the next login, there will be 20 commands from the previous session that will be saved.
You can view the history list a variety of different ways. Let's first view the last 20 commands by simply issuing the history command:
sys1 23: history 4 whoami 5 pwd 6 find / -name login -print & 7 hostname 8 who 9 more /etc/passwd 10 history 11 history 5 12 echo $PATH 13 more .login 14 cat .login 15 exit 16 exit 17 history -h 18 pwd 19 whoami 20 cd /tmp 21 cat database.log 22 cd 23 history sys1 24:
We can also print the history list without line number, as shown in the following example:
sys1 24: history -h pwd find / -name login -print & hostname who more /etc/passwd history history 5 echo $PATH more .login cat .login exit exit history -h pwd whoami cd /tmp cat database.log cd history history -h sys1 25:
Next, let's print the history list in reverse order:
sys1 25: history -r 25 history -r 24 history -h 23 history 22 cd 21 cat database.log 20 cd /tmp 19 whoami 18 pwd 17 history -h 16 exit 15 exit 14 cat .login 13 more .login 12 echo $PATH 11 history 5 10 history 9 more /etc/passwd 8 who 7 hostname 6 find / -name login -print & sys1 26:
We can also select the number of events we want to print from the history list. The following example prints only the last ten commands from the history list:
sys1 26: history 10 17 history -h 18 pwd 19 whoami 20 cd /tmp 21 cat database.log 22 cd 23 history 24 history -h 25 history -r 26 history 10 sys1 27:
You can see that you have a variety of ways to produce a list of commands previously issued. Table 11-1 summarizes the commands issued in this section.
Command | Description | Example |
---|---|---|
history | The history list is produced with each command numbered. | history |
history -h | The history list is produced without line numbers. | history -h |
history -r | The history list is produced in reverse order with each command numbered. | history -r |
history n | The last n commands from the history list are produced with each command numbered. | history 10 |
You can re-execute commands from the history list using a variety of techniques. We'll re-execute commands from the history using the most common techniques.
You can repeat the last command with !!, the second command with !2, and the last command that started with "c" with !c. Let's issue the history command to get a list of the last 20 commands and then re-execute some of them:
sys1 27: history 8 who 9 more /etc/passwd 10 history 11 history 5 12 echo $PATH 13 more .login 14 cat .login 15 exit 16 exit 17 history -h 18 pwd 19 whoami 20 cd /tmp 21 cat database.log 22 cd 23 history 24 history -h 25 history -r 26 history 10 27 history sys1 28:
Let's first re-issue the last command with !!:
sys1 28: !! history 9 more /etc/passwd 10 history 11 history 5 12 echo $PATH 13 more .login 14 cat .login 15 exit 16 exit 17 history -h 18 pwd 19 whoami 20 cd /tmp 21 cat database.log 22 cd 23 history 24 history -h 25 history -r 26 history 10 27 history 28 history sys1 29:
Let's now re-issue the 19th command with !19:
sys1 29: !19 whoami martyp2 sys1 30:
Let's now re-issue the last command beginning with "p" with !p:
sys1 30: !p pwd /home/martyp2 sys1 31:
Table 11-2 includes some of the more commonly used history list recall commands.
Command | Description | Example |
---|---|---|
!N | Issue command N | !2 |
!! | Issue last command | !! |
!-N | Issue Nth command from last command issued | !-N |
!str | Issue last command starting with str | !c |
!?str? | Issue last command that had str anyplace in command line | !?cat? |
!{str}str2 | Append str2 to last command with str1 | !{cd} /tmp |
^str1^str2^ | Substitute str2 for str1 in last command | ^cat^more^ |
An alias is a name that you select for a frequently used command or series of commands. Many aliases are predefined for you.
You can use the.cshrc file as a place where your aliases are stored and read every time you log in. You can also define aliases at the command-line prompt, but these are cleared when you log out.
The alias command, without any arguments, lists all aliases. This list includes both preset aliases as well as those you have set. The following alias command shows all preset aliases on the system on which I am working:
sys1 7: alias d dirs m more pd pushd pd2 (pushd +2) po popd status (date; bdf) sys1 8:
You are not restricted to using only the preset aliases. To create your own alias, you first issue the alias command, the name of the alias, and then the command or commands that are executed when the alias is executed.
Let's now create a few simple aliases. The first creates an alias of "h" for the history command:
sys1 1: alias h history sys1 2: h history
Every time you type h, the history command is executed.
The following example creates an alias of a command that contains spaces, so the command is surrounded by single quotes:
alias ls='ls -al' alias ls
The first command creates an alias for "ls" that executes the ls -al command. We then issued the alias command to see whether indeed the new alias appears in the list of aliases. Then we run ls to see whether ls -al is run.
You don't have to keep an alias for the duration of your session after having set it. If you don't like an alias, you can use the unalias command to remove an alias.
To see unalias work let's again produce a list of aliases, use unalias to unset the h alias, and run the h command to see if indeed it has been removed.
unalias h h
When we issued unalias to remove the h alias and then try to run h, we were told that h is not found.
sys1 3:alias procs 'echo "Number of processes are: \c"; ps -ef | wc -l' # single quote on outside # double quote on inside
When you run procs, you see the following:
sys1 4: procs Number of processes are: 44
A lot of quoting takes place in this command line. To understand what is taking place on this line, turn to Table 11-3 for help.
Character(s) | Description |
---|---|
'cmd' | Single quote means to take the string character literally |
"str" | Double quote means to allow command and variable substitution |
\c | Escape character that prevents everything following it from printing, including new line |
'str' | Grave means to execute command and substitute output |
Applying Table 11-3 to the earlier procs alias, we can see what comprises this alias. The alias begins with a single quote, which means execute the command(s) within the single quotes. The first command is the echo command, which uses double quotes to specify the characters to echo. Embedded in the double quotes is the escape character \c, which prevents a new line from being printed. The semicolons separate commands. ps is then run to produce a list of processes, and the output is piped (|) to word count (wc) which produces a count of the number of lines. There are actually 43 processes running, because an extra line consisting of the ps headings is reported by wc.
As you can see in Figure 11-3, some of the quoting becomes tricky. An understanding of quoting is important if you wish to modify and reuse existing shell scripts or craft your own.
Another important part of using the C shell is file-name expansion. When we cover shell programming, you will surely be preparing shell scripts that deal with file names. An overview of file-name expansion is useful to ensure that you're comfortable with this topic before you start writing shell scripts.
Table 11-4 lists some common file-name expansion and pattern matching.
Character(s) | Example | Description |
---|---|---|
* | 1) ls *.c | Match zero or more characters |
? | 2) ls conf.? | Match any single character |
[list] | 3) ls conf.[co] | Match any character in list |
[lower-upper] | 4) ls libdd.9873[5-6].sl | Match any character in range |
str{str1,str2,str3,...} | 5) ls ux*.{700,300} | Expand str with contents of {} |
~ | 6) ls -a ~ | Home directory |
~username | 7) ls -a ~gene | Home directory of username |
The following are expanded descriptions of the examples shown in Table 11-4:
To list all files in a directory that end in ".c," you could do the following:
sys1 30: ls *.c conf. SAM.c conf.c
To find all the files in a directory named "conf" with an extension of one character, you could do the following:
sys1 31: ls conf.? conf.c conf.o conf.1
To list all the files in a directory named "conf" with only the extension "c" or "o," you could do the following:
sys1 32: ls conf.{co} conf.c conf.o
To list files with similar names but with a specific field that covers a range, you could do the following:
sys1 46: ls libdd9873[5-6].sl libdd98735.sl libdd98736.sl
To list files that start with "ux" and have the extension "300" or "700," you could do the following:
sys1 59: ls ux*.{700,300} uxbootlf.700 uxinstfs.300 unistkern.300 unistkern.700 unistlf.700
To list the files in your home directory, you could use ~ as shown below:
sys1 62: ls -a ~ . .cshrc.org .login .shrc.org .. .exrc .login.org .vue .chsrc .history .profile .vueprofile
To list the files in the home directory of a user, you can do the following:
sys1 65: ls -a ~gene . .history .vue splinedat .. .login .vueprofile trail.txt .chsrc .login.org ESP-File under.des .cshrc.org .profile Mail xtra.part .exrc .shrc.org opt
Many of these techniques are useful when writing shell scripts, so you want to become familiar with file-name expansion.
UNIX is set up such that commands usually take their input from the keyboard, often called standard input, and usually send output to the screen, often called standard output. Commands also send error information to the screen. You do not always want input to come from standard input and output and errors to go to standard output. You are given a lot of control to override these defaults. This is called redirection. Table 11-5 shows many common forms of redirection.
As shown in the table, to redirect the output of a command from standard output to a file, you would use ">". This works almost all of the time. If you have an environment variable called noclobber set, then redirecting to an existing file does not work. The noclobber does not permit redirection to write over an existing file. If you try to write over an existing file, such as/tmp/processes below, you receive a message that the file exists:
# ps -ef > /tmp/processes /tmp/processes: File exists
You can, however, use a "!" with redirection to force a file to be overwritten. Using ">!" forces a file to be overwritten, and ">>!" will force the output to be appended to the end of an existing file. Examples of these are shown in the Table 11-5.
Command or Assignment | Example | Description |
---|---|---|
< | wc-l<.login | Standard input redirection:execute wc (word count) and list number of lines (-l) in. login |
> | ps -ef > /tmp/processes | Standard output redirection: execute ps and send outputto file/tmp/processes |
>> | ps -ef >> /tmp/processes | Append standard output: execute ps and append outputto theend offile /tmp/processes |
>! | ps -ef >! /tmp/processes | Standard output redirection and override noclobber: write over /tmp/processes even if it exists |
>>! | ps -ef >>! /tmp/processes | Append standard output and override noclobber: append to the end of /tmp/processes |
| (pipe) | ps wc -l | Run ps and use the result as input to wc |
0 -standard input | ||
1 -standard output | ||
2 -standard error | cat program 2> errors | cat the file program to standard output and redirect errors to the file errors |
cat program 2>> errors | cat the file program to standard output and append errors to the file errors | |
cat program >& outfile | cat both the file program and errors to the file outfile | |
(cat program > outfile) >& errors | cat the file program to outfile and redirect errors to the file errors |
You are indeed special to your UNIX system. Information about your user environment in the C shell is stored in shell variables and environment variables.
Shell variables are sometimes called "local" variables. Shell variables are known only to the shell in which they were created.
Environment variables are sometimes called "global" variables. Environment variables are defined in the shell where they are created and are inherited by all shells spawned from the original shell. Because these variables are passed to shells spawned from the original shell, they are considered global.
You can view shell variables with the set command and environment variables with the env command, as shown below:
sys1 22: set argv () autologout 600 cwd /home/martyp2 history 20 home /home/martyp2 noclobber path (/usr/bin /usr/ccs/bin /usr/contrib/bin /opt/net- tladm/bin /opt/pd/bin /) prompt sys1 !: savehist 20 shell /usr/bin/csh status 0 system sys1 term vt100 sys1 23: set argv () autologout 600 cwd /home/martyp2 history 20 home /home/martyp2 noclobber path (/usr/bin /usr/ccs/bin /usr/contrib/bin /opt/net- tladm/bin /opt/pd/bin /) prompt sys1 !: savehist 20 shell /usr/bin/csh status 0 system sys1 term vt100 sys1 24:
sys1 24: env HOME=/home/martyp2 PATH=/usr/bin:/usr/ccs/bin:/usr/contrib/bin:/opt/net- tladm/bin:/opt/pd/bin:/opt/n LOGNAME=martyp2 TERM=vt100 SHELL=/usr/bin/csh MAIL=/var/mail/martyp2 COLUMNS=80 LINES=24 MANPATH=/usr/share/man/%L:/usr/share/man:/usr/contrib/ man/%L:/usr/contrib/man:/n TZ=PST8PDT sys1 25:
Notice that local variables are in lower case and global variables are in uppercase by convention.
You can see from having issued the set command that many local and global variables have been set. You can determine whether a variable has been set by using the special notation $?. Placing this special notation in front of a variable name returns a 1 if the variable has been set and a 0 if the variable has not been set. The following example shows using echo and this special notation to see whether the variables history and hist have been set:
sys1 25: echo $?history 1 sys1 26: echo $?hist 0 sys1 27:
Because a 1 was returned from the history variable, we know that this variable was indeed set. We can confirm this from the earlier output of the set command, which showed that history was set to 20.
Because a 0 was returned from the hist variable, we know that this variable is not set.
Using the special metacharacter $, we tell the shell to extract the value of a variable. The following example uses echo combined with $ preceding the history variable to report its value:
sys1 27: echo $history 20 sys1 28: echo $hist hist: Undefined variable. sys1 29:
Shell variables are defined using set. We saw in the.cshrc file earlier that the history shell variable is set with the following command:
set history = 20
Environment variables are defined with setenv, as in the following command:
setenv EDITOR vi
When you run a command, as we have done so far in many examples, you don't get back the prompt until the command has completed. These commands have been run in the foreground. Some commands can take a long time to complete, in which case you wait a long time for the prompt to return. As an alternative to waiting for the prompt to return, you can run the command in the background, which means it is running behind the scenes while you perform other work. Because UNIX is multi-tasking, it is happy to run many commands in the background and still provide you with a prompt to issue yet more commands.
In order to run a command in the background, you simply add an ampersand (&) to the end of the command line. When you follow your command with an ampersand, the command is run in the background and the prompt is immediately returned.
Let's now run some commands on our Solaris system. We'll first run a command to find all the files in /usr that end in ".c," which takes some time to complete. We'll preface the find string with the time command so that we know how long the command takes to complete:
martyp $ time find /usr -name *.c . . . /usr/demo/link_audit/src/dumpbind.c /usr/demo/link_audit/src/env.c /usr/demo/link_audit/src/hash.c /usr/demo/link_audit/src/perfcnt.c /usr/demo/link_audit/src/symbindrep.c /usr/demo/link_audit/src/truss.c /usr/demo/link_audit/src/who.c find: cannot read dir /usr/aset: Permission denied real 1m21.04s user 0m1.51s sys 0m12.67s
This command took roughly one minute and 21 seconds to complete. Because it was not run in the foreground, we were unable to issue any other commands while it was running, because we had to wait for the prompt to return.
An alternative to running the command in the foreground is to issue the command followed by an ampersand, in which case the job runs in the background and the prompt returns immediately, as shown in the following example:
martyp $ time find /usr -name *.c > cprogs 2>&1 & [3] 16279 martyp $ real 2m10.20s user 0m1.31s sys 0m8.62s
The result of running this command in the background produces a job number in brackets and the process id, or PID, as the second number. All the output of this command, including errors, are written to the file cprogs. The prompt was immediately returned after we issued the command and after it completed, the output of time was sent to the screen. We could have begun issuing additional commands immediately after issuing the command in the background.
You have control over both foreground jobs and background jobs. To suspend a foreground job, you type the "control" and "z" keys simultaneously, as shown in the following example:
martyp $ find /usr -name *.c /usr/openwin/share/include/X11/Xaw/Template.c /usr/openwin/share/src/dig_samples/DnD/main.c /usr/openwin/share/src/dig_samples/DnD/owner.c /usr/openwin/share/src/dig_samples/DnD/requestor.c /usr/openwin/share/src/dig_samples/Tooltalk/olit_tt.c /usr/openwin/share/src/dig_samples/Tooltalk/ tt_callbacks.c /usr/openwin/share/src/dig_samples/Tooltalk/tt_code.c /usr/openwin/share/src/dig_samples/ce1/ce_map1.c /usr/openwin/share/src/dig_samples/ce2/ce_simple.c /usr/openwin/share/src/dig_samples/dnd_olit/olitdnd.c /usr/openwin/share/src/dig_samples/dnd_xview1/ xview_dnd.c /usr/openwin/share/src/dig_samples/dnd_xview2/ xview_dnd2.c /usr/openwin/share/src/dig_samples/selection_olit/ olit_sel.c /usr/openwin/share/src/dig_samples/tooltalk_simple/ tt- send.c /usr/openwin/share/src/olit/oldials/oldials.c /usr/openwin/share/src/olit/olitbook/ch10/draw.c ^Z[3] + Stopped (SIGTSTP) find /usr -name *.c
After ctrl-z is pressed, the find command is interrupted at the point at which you type ctrl-z. The command is suspended at this point and you are shown the job number, in this case "3," and its status is listed as "Stopped." This command has only been suspended; it is not gone forever. You can restart this process in the foreground with fg or run it in the background with bg. Usingbg runs the command as if you had followed it with an "&". It is started from the point at which you interrupted it. You do not have to supply a job number when you issue the fg or bg command, because the default is to perform the specified operation on the last job, which in this case is job number 3.
Notice that in this example we have stopped job number 3. This means that there are other jobs running with a lower job number. You can use the jobs command to get a list of all jobs and their status. You can then control the jobs by issuing commands: such as fg followed by a "%" and the job number to run the command in the foreground, or a bg followed by a "%" and the job number to run the command in the background. If you wish to terminate a job altogether, you can issue the kill command followed by a "%" and the job number.
In the process of creating the examples in this section, I have started and suspended many jobs. The following example shows listing all jobs with the jobs command, killing jobs 1 and 2 with kill, and running job 3 in the background:
martyp $ jobs [3] + Stopped (SIGTSTP) find /usr -name *.c [2] - Running time find / -name gnu* > gnu 2>&1 & [1] Running time find / -name *.c > cprogs 2>&1 & martyp $ kill %1 [1] Terminated time find / -name *.c > cprogs 2>&1 & martyp $ kill %2 [2] - Terminated time find / -name gnu* > gnu 2>&1 & martyp $ bg %3 [3] find /usr -name *.c& martyp $
Notice that an ampersand was added to job 3 when we requested that it be run in the background. Killing jobs 1 and 2 and running job 3 in the background return the prompt so that you can perform additional work.
An additional topic to cover related to csh is file permissions and the way they relate to umask. This is important because you may write shell programs, and the permissions control the access that others have to these programs. umask is used to specify permission settings for new files and directories.
Let's start with an example of a long listing of a file. We'll use ls -l in the following examples:
sys1 1: ls -l script1 -rwxr-xr-x 1 marty users 120 Jul 26 10:20 script1
The access rights for this file are defined by the position of read (r), write (w), and execute (x) when the ll command is issued. Figure 11-4 shows the three groups of three access rights for this file.
The owner of this file has read, write, and execute permissions on the file. The group to which the user belongs has read and execute permissions, and others also have read and execute permissions. The permissions on this file can be specified by the octal sum of each field, which is 755.
What happens if you craft a new shell script or any new file? What permission settings exist? You want to execute the shell script, so you will need execute permission for the file. You can use umask to define the defaults for all your new files and directories.
By default, most systems start with a permission of 777 for directories and 666 for files. This means that everyone has complete access to all directories you create and everyone has read and write access to all files you create. These defaults are modified with the value of umask.
You can view your umask in the following two ways:
martyp $ umask 002 martyp $ umask -S u=rwx,g=rwx,o=rx martyp $
The first example displays the octal value of umask, which we'll cover shortly, and the second example shows the symbolic value of umask. The-S does not work on all UNIX variants.
The umask is used to disable access. You start with a umask and use the fields to disable some level of access. The umask command uses three octal fields. The fields are the sum of the access codes for user, group, and other, as shown in Figure 11-5.
The complement of the umask field is "anded" with the default setting to change the umask. You can set umask by specifying its value. In our earlier example we viewed umask two different ways. To set the umask, you simply issue umask and the desired value. Setting umask to 022, for example, removes write permissions of directories for "group" and "other," as shown in Figure 11-6.
umask 022 changes the directory permissions to 755 in this example.
Similarly, a umask of 022 changes the default permission of 666 for files to 644, which is read-only for group and other.
The chmod command is used to change the permissions on a file. Irre-spective of what takes place with umask, as just described, you can change a file's permissions at any time with chmod. You need to be the owner of the file or superuser to change a file's permissions with chmod in most cases. Let's start our discussion of chmod with the listing of the file sort:
$ ls -l sort -rwxr-x--x 1 marty users 120 Jul 26 10:20 sort
Figure 11-7 shows a breakdown of the permissions on sort.
You have very little control over the type of file defined. You do, however, have a great deal of control over the permissions of this file if it belongs to you. The chmod command is used to change the permissions on a file or directory. If you are the owner of the file, you can have a field day changing the permissions on the file.
There are two means by which you can change the permissions: symbolic or numeric. I'll focus first on the numeric mode, because the numbers involved are easy to manage and I sometimes find that new UNIX users get hung up on the meaning of some of the symbols. I'll then cover the symbols and include the symbol meanings in the chmod summary.
First of all, what do I mean by numbers? Looking at the numbers for sort, we see permissions of 751: 7 for owner (hundreds position), 5 for group (tens position), and 1 for other (ones position). Figure 11-8 helps with the meanings of the positions.
Selecting the desired permissions for owner, group, and other, you use the chmod command to assign those permissions to a file or directory. Some of these permission possibilities are infrequently used, such as execute only, because you usually need to have read access to a file in order to execute it; however, I included all possibilities in Figure 11-8 for completeness. In addition to the permission mode bits shown in Figure 11-8, miscellaneous mode bits also exist which you don't need to be concerned with at this time.
If you decided that you would like to add write permission of the file sort for group, and remove all permissions for other, you would simply execute the chmod command with the appropriate numeric value. The following set of commands first list the existing permissions for sort, next change the permissions on sort, and finally list the new permissions on sort:
$ ls -l sort -rwxr-x--x 1 marty users 120 Jul 26 10:20 sort $ chmod 770 sort $ ls -l sort -rwxrwx--- 1 marty users 120 Jul 26 10:20 sort
The same set of commands to change the permissions using the symbolic mode would be:
$ ls -l sort -rwxr-x--x 1 marty users 120 Jul 26 10:20 sort $ chmod g+w,o-x sort $ ls -l sort -rwxrwx--- 1 marty users 120 Jul 26 10:20 sort
In symbolic mode, you issue the chmod command and specify who will be affected by the change [user (u), group (g), other (o), or all (a)], the operation you wish to perform [add (+), delete (-), or replace (=)], and the permission you wish to specify [read (r), write (w), or execute (x)]. In the previous example using symbolic mode, write (w) permission is being added (+) for group (g), and execute (x) permission is being removed (-) for other (o).
The following is a summary of some of the more commonly used symbols of chmod:
chmod - Change permissions of specified files using the following symbolic mode list.
|
The C shell functionality covered in this chapter combined with the following manual pages, should get you off to a good start with the C shell.
The following is the HP-UX manual page for csh. Commands often differ among UNIX variants, so you may find differences in the options or other areas for this manual page; however, the following manual page serves as an excellent reference.
csh - C shell.
csh(1) csh(1) NAME csh - a shell (command interpreter) with C-like syntax SYNOPSIS csh [-cefinstvxTVX] [command_file] [argument_list ...] DESCRIPTION csh is a command language interpreter that incorporates a command history buffer, C-like syntax, and job control facilities. Command Options Command options are interpreted as follows: -c Read commands from the (single) following argument which must be present. Any remaining arguments are placed in argv. -e C shell exits if any invoked command terminates abnormally or yields a non-zero exit status. -f Suppress execution of the .cshrc file in your home directory, thus speeding up shell start-up time. -i Force csh to respond interactively when called from a device other than a computer terminal (such as another computer). csh normally responds non-interactively. If csh is called from a computer terminal, it always responds interactively, regardless of which options are selected. -n Parse but do not execute commands. This is useful for checking syntax in shell scripts. All substitutions are performed (history, command, alias, etc.). -s Take command input from the standard input. -t Read and execute a single line of input. -v Set the verbose shell variable, causing command input to be echoed to the standard output device after history substitutions are made. -x Set the echo shell variable, causing all commands to be echoed to the standard error immediately before execution. -T Disable the tenex features which use the ESC key for command/file name completion and CTRL-D for listing available files (see the CSH UTILITIES section below) -V Set the verbose variable before .cshrc is executed so that all .cshrc commands are also echoed to the standard output. -X Set the echo variable before .cshrc is executed so that all .cshrc commands are also echoed to the standard output. After processing the command options, if arguments remain in the argument list, and the -c, -i, -s, or -t options were not specified, the first remaining argument is taken as the name of a file of commands to be executed. COMMANDS A simple command is a sequence of words, the first of which specifies the command to be executed. A sequence of simple commands separated by vertical bar (|) characters forms a pipeline. The output of each command in a pipeline becomes the input for the next command in the pipeline. Sequences of pipelines can be separated by semicolons (;) which causes them to be executed sequentially. A sequence of pipelines can be executed in background mode by adding an ampersand character (&) after the last entry. Any pipeline can be placed in parentheses to form a simple command which, in turn, can be a component of another pipeline. Pipelines can also be separated by || or && indicating, as in the C language, that the second pipeline is to be executed only if the first fails or succeeds, respectively. Jobs csh associates a job with each pipeline and keeps a table of current jobs (printed by the jobs command) and assigns them small integer numbers. When a job is started asynchronously using &, the shell prints a line resembling: [1] 1234 indicating that the job which was started asynchronously was job number 1 and had one (top-level) process, whose process id was 1234. If you are running a job and want to do something else, you can type the currently defined suspend character (see termio(7)) which sends a stop signal to the current job. csh then normally indicates that the job has been `Stopped', and prints another prompt. You can then manipulate the state of this job, putting it in the background with the bg command, run some other commands, and then eventually bring the job back into the foreground with the foreground command fg. A suspend takes effect immediately and is like an interrupt in that pending output and unread input are discarded when it is typed. There is a delayed suspend character which does not generate a stop signal until a program attempts to read(2) it. This can usefully be typed ahead when you have prepared some commands for a job which you want to stop after it has read them. A job being run in the background stops if it tries to read from the terminal. Background jobs are normally allowed to produce output, but this can be disabled by giving the command stty tostop (see stty(1)). If you set this tty option, background jobs stop when they try to produce output, just as they do when they try to read input. Keyboard signals and line-hangup signals from the terminal interface are not sent to background jobs on such systems. This means that background jobs are immune to the effects of logging out or typing the interrupt, quit, suspend, and delayed suspend characters (see termio(7)). There are several ways to refer to jobs in the shell. The character % introduces a job name. If you wish to refer to job number 1, you can name it as %1. Just naming a job brings it to the foreground; thus %1 is a synonym for fg %1 , bringing job 1 back into the foreground. Similarly, typing %1 & resumes job 1 in the background. Jobs can also be named by prefixes of the string typed in to start them if these prefixes are unambiguous; thus %ex normally restarts a suspended ex(1) job, if there is only one suspended job whose name begins with the string ex. It is also possible to say %?string which specifies a job whose text contains string, if there is only one such job. csh maintains a notion of the current and previous jobs. In output pertaining to jobs, the current job is marked with a + and the previous job with a -. The abbreviation %+ refers to the current job and %- refers to the previous job. For close analogy with the syntax of the history mechanism (described below), %% is also a synonym for the current job. csh learns immediately whenever a process changes state. It normally informs you whenever a job becomes blocked so that no further progress is possible, but only just before printing a prompt. This is done so that it does not otherwise disturb your work. If, however, you set the shell variable notify, csh notifies you immediately of changes in status of background jobs. There is also a csh built-in command called notify which marks a single process so that any status change is immediately reported. By default, notify marks the current process. Simply type notify after starting a background job to mark it. If you try to leave the shell while jobs are stopped, csh sends the warning message: You have stopped jobs. Use the jobs command to see what they are. If you do this or immediately try to exit again, csh does not warn you a second time, and the suspended jobs are terminated (see exit(2)). Built-In Commands Built-in commands are executed within the shell without spawning a new process. If a built-in command occurs as any component of a pipeline except the last, it is executed in a subshell. The built-in commands are: alias alias name alias name wordlist The first form prints all aliases. The second form prints the alias for name. The third form assigns the specified wordlist as the alias of name. Command and file name substitution are performed on wordlist. name cannot be alias or unalias. bg [%job ...] Put the current (job not specified) or specified jobs into the background, continuing them if they were stopped. break Causes execution to resume after the end of the nearest enclosing foreach or while. The remaining commands on the current line are executed. Multi-level breaks are thus possible by writing them all on one line. breaksw Causes a break from a switch, resuming after the endsw. case label: A label in a switch statement as discussed below. cd cd directory_name chdir chdir directory_name Change the shell's current working directory to directory_name. If not specified, directory_name defaults to your home directory. If directory_name is not found as a subdirectory of the current working directory (and does not begin with /, ./, or ../), each component of the variable cdpath is checked to see if it has a subdirectory directory_name. Finally, if all else fails, csh treats directory_name as a shell variable. If its value begins with /, this is tried to see if it is a directory. continue Continue execution of the nearest enclosing while or foreach. The rest of the commands on the current line are executed. default: Labels the default case in a switch statement. The default should come after all other case labels. dirs Prints the directory stack; the top of the stack is at the left; the first directory in the stack is the current directory. echo wordlist echo -n wordlist The specified words are written to the shell's standard output, separated by spaces, and terminated with a new line unless the -n option is specified. else end endif endsw See the descriptions of the foreach, if, switch, and while statements below. eval arguments ... (Same behavior as sh(1).) arguments are read as input to the shell and the resulting command(s) executed. This is usually used to execute commands generated as the result of command or variable substitution, since parsing occurs before these substitutions. exec command The specified command is executed in place of the current shell. exit exit (expression) csh exits either with the value of the status variable (first form) or with the value of the specified expression (second form). fg [%job ...] Brings the current (job not specified) or specified jobs into the foreground, continuing them if they were stopped. foreach name (wordlist) ... end The variable name is successively set to each member of wordlist and the sequence of commands between this command and the matching end are executed. (Both foreach and end must appear alone on separate lines.) The built-in command continue can be used to continue the loop prematurely; the built-in command break to terminate it prematurely. When this command is read from the terminal, the loop is read once, prompting with ? before any statements in the loop are executed. If you make a mistake while typing in a loop at the terminal, use the erase or line-kill character as appropriate to recover. glob wordlist Like echo but no \ escapes are recognized and words are delimited by null characters in the output. Useful in programs that use the shell to perform file name expansion on a list of words. goto word The specified word is file name and command expanded to yield a string of the form label. The shell rewinds its input as much as possible and searches for a line of the form label: possibly preceded by blanks or tabs. Execution continues after the specified line. hashstat Print a statistics line indicating how effective the internal hash table has been at locating commands (and avoiding execs). An exec is attempted for each component of the path where the hash function indicates a possible hit, and in each component that does not begin with a /. history [-h] [-r] [n] Displays the history event list. If n is given, only the n most recent events are printed. The -r option reverses the order of printout to be most recent first rather than oldest first. The -h option prints the history list without leading numbers for producing files suitable for the source command. if (expression) command If expression evaluates true, the single command with arguments is executed. Variable substitution on command happens early, at the same time it does for the rest of the if command. command must be a simple command; not a pipeline, a command list, a parenthesized command list, or an aliased command. Input/output redirection occurs even if expression is false, meaning that command is not executed (this is a bug). if (expression1) then ... else if (expression2) then ... else ... endif If expression1 is true, all commands down to the first else are executed; otherwise if expression2 is true, all commands from the first else down to the second else are executed, etc. Any number of else-if pairs are possible, but only one endif is needed. The else part is likewise optional. (The words else and endif must appear at the beginning of input lines. The if must appear alone on its input line or after an else.) jobs [-l] Lists active jobs. The -l option lists process IDs in addition to the usual information. kill % job kill - sig % job ... kill pid kill - sig pid... kill -l Sends either the TERM (terminate) signal or the specified signal to the specified jobs or processes. Signals are either given by number or by names (as given in /usr/include/signal.h, stripped of the SIG prefix (see signal(2)). The signal names are listed by kill -l. There is no default, so kill used alone does not send a signal to the current job. If the signal being sent is TERM (terminate) or HUP (hangup), the job or process is sent a CONT (continue) signal as well. limit[-h][resource][maximum_use] Limits the usage by the current process and each process it creates not to (individually) exceed maximum_use on the specified resource. If maximum_use is not specified, then the current limit is displayed; if resource is not specified, then all limitations are given. If the -h flag is specified, the hard limits are used instead of the current limits. The hard limits impose a ceiling on the values of the current limits. Only the superuser can raise the hard limits, but a user can lower or raise the current limits within the legal range. Controllable resources currently include: addresspace Maximum address space in bytes for a process coredumpsize Size of the largest core dump that is created cputime Maximum number of CPU seconds to be used by each process datasize Maximum growth of the data region allowed beyond the end of the program text descriptors Maximum number of open files for each process filesize Largest single file that can be created memoryuse Maximum size to which a process's resident set size can grow stacksize Maximum size of the automatically extended stack region The maximum_use argument can be specified as a floating- point or integer number followed by a scale factor: k or kilobytes (1024 bytes), m or megabytes, or b or blocks (the units used by the ulimit system call). For both resource names and scale factors, unambiguous prefixes of the names can be used. filesize can be lowered by an instance of csh, but can only be raised by an instance whose effective user ID is root. For more information, refer to the documentation for the ulimit system call. login Terminates a login shell, replacing it with an instance of /usr/bin/login. This is one way to log off, included for compatibility with sh(1). logout Terminates a login shell. Especially useful if ignoreeof is set. A similar function, bye, which works for sessions that are not login shells, is provided for historical reasons. Its use is not recommended because it is not part of the standard BSD csh and may not be supported in future releases. newgrp Changes the group identification of the caller; for details see newgrp(1). A new shell is executed by newgrp so that the current shell environment is lost. nice nice +number nice command nice +number command The first form sets the nice (run command priority) for this shell to 4 (the default). The second form sets the priority to the given number. The final two forms run command at priority 4 and number respectively. The user with appropriate privileges can raise the priority by specifying negative niceness using nice -number ... command is always executed in a sub-shell, and restrictions placed on commands in simple if statements apply. nohup [command] Without an argument, nohup can be used in shell scripts to cause hangups to be ignored for the remainder of the script. With an argument, causes the specified command to be run with hangups ignored. All processes executed in the background with & are effectively nohuped as described under Jobs in the COMMANDS section. notify [job ...] Causes the shell to notify the user asynchronously when the status of the current (job not specified) or specified jobs changes; normally notification is presented before a prompt. This is automatic if the shell variable notify is set. onintr [-] [label] Controls the action of the shell on interrupts. With no arguments, onintr restores the default action of the shell on interrupts, which action is to terminate shell scripts or return to the terminal command input level. If - is specified, all interrupts are ignored. If a label is given, the shell executes a goto label when an interrupt is received or a child process terminates because it was interrupted. If the shell is running in the background and interrupts are being ignored, onintr has no effect; interrupts continue to be ignored by the shell and all invoked commands. popd [+n] Pops the directory stack, returning to the new top directory. With an argument, discards the nth entry in the stack. The elements of the directory stack are numbered from 0 starting at the top. A synonym for popd, called rd, is provided for historical reasons. Its use is not recommended because it is not part of the standard BSD csh and may not be supported in future releases. pushd [name] [+n] With no arguments, pushd exchanges the top two elements of the directory stack. Given a name argument, pushd changes to the new directory (using cd) and pushes the old current working directory (as in csw) onto the directory stack. With a numeric argument, pushd rotates the nth argument of the directory stack around to be the top element and changes to that directory. The members of the directory stack are numbered from the top starting at 0. A synonym for pushd, called gd, is provided for historical reasons. Its use is not recommended since it is not part of the standard BSD csh and may not be supported in future releases. rehash Causes the internal hash table of the contents of the directories in the path variable to be recomputed. This is needed if new commands are added to directories in the path while you are logged in. This should only be necessary if you add commands to one of your own directories or if a systems programmer changes the contents of one of the system directories. repeat count command The specified command (which is subject to the same restrictions as the command in the one-line if statement above) is executed count times. I/O redirections occur exactly once, even if count is 0. set set name set name=word set name[index]=word set name=(wordlist) The first form of set shows the value of all shell variables. Variables whose value is other than a single word print as a parenthesized word list. The second form sets name to the null string. The third form sets name to the single word. The fourth form sets the indexth component of name to word; this component must already exist. The final form sets name to the list of words in wordlist. In all cases the value is command and file-name expanded. These arguments can be repeated to set multiple values in a single set command. Note, however, that variable expansion happens for all arguments before any setting occurs. setenv name value Sets the value of environment variable name to be value, a single string. The most commonly used environment variables, USER, TERM, and PATH, are automatically imported to and exported from the csh variables user, term, and path; there is no need to use setenv for these. shift [variable] If no argument is given, the members of argv are shifted to the left, discarding argv[1]. An error occurs if argv is not set or has less than two strings assigned to it. When variable is specified, shift performs the same function on the specified variable. source [-h] name csh reads commands from name. source commands can be nested, but if nested too deeply the shell may run out of file descriptors. An error in a source at any level terminates all nested source commands. Normally, input during source commands is not placed on the history list. The -h option can be used to place commands in the history list without being executing them. stop [%job ...] Stops the current (no argument) or specified jobs executing in the background. suspend Causes csh to stop as if it had been sent a suspend signal. Since csh normally ignores suspend signals, this is the only way to suspend the shell. This command gives an error message if attempted from a login shell. switch (string) case str1: ... breaksw ... default: ... breaksw endsw Each case label (str1) is successively matched against the specified string which is first command and file name expanded. The form of the case labels is the Pattern Matching Notation with the exception that non-matching lists in bracket expressions are not supported (see regexp(5)). If none of the labels match before a default label is found, the execution begins after the default label. Each case label and the default label must appear at the beginning of a line. The breaksw command causes execution to continue after the endsw. Otherwise, control may fall through case labels and default labels as in C. If no label matches and there is no default, execution continues after the endsw. time [command] When command is not specified, a summary of time used by this shell and its children is printed. If specified, the simple command is timed and a time summary as described under the time variable is printed. If necessary, an extra shell is created to print the time statistic when the command completes. umask [value] The current file creation mask is displayed (value not specified) or set to the specified value. The mask is given in octal. Common values for the mask are 002, which gives all permissions to the owner and group and read and execute permissions to all others, or 022, which gives all permissions to the owner, and only read and execute permission to the group and all others. unalias pattern All aliases whose names match the specified pattern are discarded. Thus, all aliases are removed by unalias *. No error occurs if pattern does not match an existing alias. unhash Use of the internal hash table to speed location of executed programs is disabled. unset pattern All variables whose names match the specified pattern are removed. Thus, all variables are removed by unset *; this has noticeably undesirable side-effects. No error occurs if pattern matches nothing. unsetenv pattern Removes all variables whose names match the specified pattern from the environment. See also the setenv command above and printenv(1). wait Waits for all background jobs to terminate. If the shell is interactive, an interrupt can disrupt the wait, at which time the shell prints names and job numbers of all jobs known to be outstanding. while (expression) ... end While the specified expression evaluates non-zero, the commands between the while and the matching end are evaluated. break and continue can be used to terminate or continue the loop prematurely. (The while and end must appear alone on their input lines.) If the input is a terminal (i.e., not a script), prompting occurs the first time through the loop as for the foreach statement. %job Brings the specified job into the foreground. %job & Continues the specified job in the background. @ @ name=expression @ name[index]=expression The first form prints the values of all the shell variables. The second form sets the specified name to the value of expression. If the expression contains <, >, &, or |, at least this part of the expression must be placed within parentheses. The third form assigns the value of expression to the indexth argument of name. Both name and its indexth component must already exist. The operators *=, +=, etc., are available as in C. White space can optionally separate the name from the assignment operator. However, spaces are mandatory in separating components of expression which would otherwise be single words. Special postfix ++ and -- operators increment and decrement name, respectively (e.g., @ i++). Non-Built-In Command Execution When a command to be executed is not a built-in command, csh attempts to execute the command via exec(2). Each word in the variable path names a directory in which the shell attempts to find the command (if the command does not begin with /). If neither -c nor -t is given, the shell hashes the names in these directories into an internal table so that an exec is attempted only in those directories where the command might possibly reside. This greatly speeds command location when a large number of directories are present in the search path. If this mechanism has been turned off (via unhash), or if -c or -t was given, or if any directory component of path does not begin with a /, the shell concatenates the directory name and the given command name to form a path name of a file which it then attempts to execute. Commands placed inside parentheses are always executed in a subshell. Thus (cd ; pwd) prints the home directory then returns to the current directory upon completion, whereas: cd ; pwd remains in the home directory upon completion. When commands are placed inside parentheses, it is usually to prevent chdir from affecting the current shell. If the file has execute permissions but is not an executable binary file, it is assumed to be a script file, which is a file of data for an interpreter that is executed as a separate process. csh first attempts to load and execute the script file (see exec(2)). If the first two characters of the script file are #!, exec(2) expects an interpreter path name to follow and attempts to execute the specified interpreter as a separate process to read the entire script file. If no #! interpreter is named, and there is an alias for the shell, the words of the alias are inserted at the beginning of the argument list to form the shell command. The first word of the alias should be the full path name of the command to be used. Note that this is a special, late-occurring case of alias substitution, which inserts words into the argument list without modification. If no #! interpreter is named and there is no shell alias, but the first character of the file is #, the interpreter named by the $shell variable is executed (note that this normally would be /usr/bin/csh, unless the user has reset $shell). If $shell is not set, /usr/bin/csh is executed. If no !# interpreter is named, and there is no shell alias, and the first character of the file is not #, /usr/bin/sh is executed to interpret the script file. History Substitutions History substitutions enable you to repeat commands, use words from previous commands as portions of new commands, repeat arguments of a previous command in the current command, and fix spelling or typing mistakes in an earlier command. History substitutions begin with an exclamation point (!). Substitutions can begin anywhere in the input stream, but cannot be nested. The exclamation point can be preceded by a backslash to cancel its special meaning. For convenience, an exclamation point is passed to the parser unchanged when it is followed by a blank, tab, newline, equal sign, or left parenthesis. Any input line that contains history substitution is echoed on the terminal before it is executed for verification. Commands input from the terminal that consist of one or more words are saved on the history list. The history substitutions reintroduce sequences of words from these saved commands into the input stream. The number of previous commands saved is controlled by the history variable. The previous command is always saved, regardless of its value. Commands are numbered sequentially from 1. You can refer to previous events by event number (such as !10 for event 10), relative event location (such as !-2 for the second previous event), full or partial command name (such as !d for the last event using a command with initial character d), and string expression (such as !?mic? referring to an event containing the characters mic). These forms, without further modification, simply reintroduce the words of the specified events, each separated by a single blank. As a special case, !! is a re-do; it refers to the previous command. To select words from a command, use a colon (:) and a designator for the desired words after the event specification. The words of an input line are numbered from zero. The basic word designators are: 0 First word (i.e., the command name itself). n nth word. ^ First argument. (This is equivalent to 1.) $ Last word. a-b Range of words from a through b. Special cases are -y, an abbreviation for ``word 0 through word y''; and x-, which means ``word x up to, but not including, word $''. * Range from the second word through the last word. % Used with a search sequence to substitute the immediately preceding matching word. The colon separating the command specification from the word designator can be omitted if the argument selector begins with a ^, $, *, -, or %. After word designator can be followed by a sequence of modifiers, each preceded by a colon. The following modifiers are defined: h Use only the first component of a path name by removing all following components. r Use the root file name by removing any trailing suffix (.xxx). e Use the file name's trailing suffix (.xxx) by removing the root name. s /l/r substitute the value of r for the value l in the indicated command. t Use only the final file name of a path name by removing all leading path name components. & Repeat the previous substitution. p Print the new command but do not execute it. q Quote the substituted words, preventing further substitutions. x Like q, but break into words at blanks, tabs and newlines. g Use a global command as a prefix to another modifier to cause the specified change to be made globally. All words in the command are changed, one change per word, and each string enclosed in single quotes (') or double quotes (") is treated as a single word. Unless preceded by a g, the modification is applied only to the first modifiable word. An error results if a substitution is attempted and cannot be completed (i.e., if you ask for a substitution of !11 on a history buffer containing only 10 commands). The left hand side of substitutions are strings; not regular expressions in the sense of HP-UX editors. Any character can be used as the delimiter in place of a slash (/). Use a backslash to quote a delimiter character if it is used in the l or r string. The character & in the right-hand side is replaced by the text from the left. A \ also quotes &. A null l string uses the previous string either from an l or from a contextual scan string s in !?s?. The trailing delimiter in the substitution can be omitted if a new-line character follows immediately, as may the trailing ? in a contextual scan. A history reference can be given without an event specification (as in !$). In this case, the reference is to the previous command unless a previous history reference occurred on the same line, in which case this form repeats the previous reference. Thus !?foo?^ !$ gives the first and last arguments from the command matching ?foo?. A special abbreviation of a history reference occurs when the first non-blank character of an input line is a circumflex (^). This is equivalent to !:s^, providing a convenient shorthand for substitutions on the text of the previous line. Thus ^lb^lib fixes the spelling of lib in the previous command. Finally, a history substitution can be enclosed within curly braces { } if necessary to insulate it from the characters which follow. Thus, after ls -ld ~paul one could execute !{l}a to do ls -ld ~paula while !la would look for a command starting with la.
CONTENTS |