Introduction to C Shell
Every Programmer C shell is a command language interpreter created by Bill Joy at the University of California at Berkeley. It is the standard shell, which is provided with BSD 4.1 and BSD 4.2 versions of UNIX. You can invoke the C shell by typing csh at the command prompt, just as sh is the name of the program for Bourne shell.
- The C shell has two main advantages over Bourne shell:
- The C shell provides a command history feature that allows rerunning (and altering) previous commands. It is so because C shell keeps track of all commands issued at the command line. It processes job control system effectively that allows processes to be moved from foreground to background or vice versa. No doubt, it would save your time on the typing work.
- This history feature is similar to DosKey in MS-DOS environment.
- The C shell provides an aliasing of commands. By using aliasing facility, you can set up shorthand notations for commands. Now you don’t need to remember lengthy commands in this shell. You can simply type the short alias at the command line, instead of typing the full name of the command.
Anyhow whatever may be the difference between the C shell and the Bourne shell, both have many common features, such as:
- Shell variables
- I/O redirection
- Filename expansion
- Command substitution
- Programmability
However the concept of shell variable is same in the Bourne shell and C shell, but the C shell handles these variables somewhat differently.
- We know that when you log in a Bourne shell version of UNIX system, it creates a sh process for you to interpret your commands. Similarly when you log in a C shell version of UNIX system, it creates a csh process for you to interpret your commands. Typically the C shell displays a % prompt instead of $ prompt of the Bourne shell.
- You can also create a sub-shell of either type. If you want to create a Bourne shell then just type sh and for C shell you type csh. But either type of sub-shell is terminated by pressing Ctrl and d keys simultaneously. Note that the login shell is typically terminated by the logout command.
- If you want to know your login shell then check the contents of /etc/passwd file. You can invoke one type of shell even if your login shell is different. It means that if your login shell is csh, you still invoke the Bourne shell by typing sh.
Shell Variables
- The shell variables are an integral part of shell programming. The shell program uses shell variables to store and manipulate information within it. Therefore a shell variable is a name associated with a value. You may create any number of variables.
- Like a Bourne shell variable, a C shell variable name must begin with either a letter (uppercase or lowercase) or an underscore (_) and followed by any combination of letters, underscore characters or numeric characters.
- The shell variable’s names should be of any reasonable length. Note that no commas or blanks are allowed within a shell variable name.
For example,
- area
- _flag
- file20
- out_file
Like Bourne shell, the C shell provides two types of shell variables:
- System Shell Variables
- User-defined Shell Variables
System Shell Variables
The variables, which are defined by the UNIX operating system for its own use, are called as system shell variables. You can use the system shell variables and can also assign different values to these system variables.
The complete list of all system variables and their respective values can be listed by using the set command as:
% set
Some of the commonly used system variables are as:
home, path, term, user, exinit, logname, mail, pwd, shell and so on.
The meanings of these variables are already defined in the Bourne shell.
User-defined Shell Variables
The variables which are created by the user for its sake of convenience are called as user-defined shell variables. The user-defined shell variables can be of any reasonable length. The user-defined shell variables are again of two types:
- Regular variables
- Environment variables
Regular Variables
Regular variables are local variables, which are set by using the set command. For example, the statement
% set num=10
defines a regular variable num, and has assigned a value “10” to it. Unlike the Bourne shell, the C shell permits spaces as:
% set num = 10
But you can use the value of a shell variable in the same way as you have in the Bourne shell; just prefixing a $ sign with the variable num as:
% echo $num10
%
Note that all shell variables are treated as string variables. Here the “10” is treated as a string of characters ‘1’ and ‘0’.
You can remove the definition of a shell variable by using the unset command as:
% unset num
You can also assign a string of more than one word to a regular shell variable using single quotes or double quotes.
% set name = ‘Suman Sagar’ using single quotes% echo My names is $name.
My name is Suman Sagar
% set name = “Suman Sagar” using double quotes
% echo My names is $name.
My name is Suman Sagar
You can also achieve the same
% set name = (Suman Sagar) using parentheses% echo My names is $name.
My name is Suman Sagar
A shell variable which has been defined but has not been given any value is known as a null variable. Following are the ways of creating a null variable
% set name% set name=‘ ’
% set name=“ ”
When you echo a null variable, only a blank line would appear on the screen.
You can also access the individual words in a string of multi words value to a shell variable as:
% echo ${name[2]}
Sagar
% echo ${name[2]}, $name[1]
Sagar Suman
The only necessary condition in this is that the string should be enclosed in parentheses; instead of single quotes or double quotes. You can also count number of words in a shell variable as:
% echo ${#name}
2
You can also include a range of words by using a hyphen as:
%set text = (A man without patience is a lamp without oil.)% echo ${text[2-7]}
man without patience is a lamp
If you omit the first number of ranges as:
% echo ${text[-7]}
then the missing number is assumed to be 1. Thus the above statement would display :
A man without patience is a lamp
On the other hand, if you omit the last number then it is supposed to be the total number of words. Thus the following statement
% echo ${text[7-]}
would display lamp without oil.
You can display the list of all current regular shell variables and their values by using the set command as:
% set
All regular variables are local to the shell in which they are defined. They are not available to sub-shells. Unfortunately, the C shell has no export command. But thanks Bill Joy, he added the setenv command to make a variable global.
Environment Variables
The variables which are created by a user in a shell and known to all sub-shells are known as environment variables. Here you may think that environment variables are similar to export variables. But it is not true.
In an exported variable if you make any change in its value in a child shell then this changed value would not be reflected back to a parent shell. On the other hand, if you make any change in the value of an environment variable then it would be reflected in back to a parent shell.
Environment variables are assigned as:
setenv shell_varaible value
For example,
% setenv name Suman% echo $name
Suman
%
Note that you should not use an equal sign in the definition of an environment variable. Here you have used the echo command to display the value of an environment variable. But suppose you have a regular variable of the same name, but different values as:
% setenv name Suman% set name = Sagar
then what do you expect the output of the following echo command
% echo $name
Suman or Sagar. Here the output would be Sagar. It is because whenever there is a conflict between a regular variable and an environment variable, it is the regular variables who wins the race. Therefore if you want to display the value of an environment varaible then use the printenv command as:
% setenv name Suman% set name = Sagar
% echo $name
Sagar
% printenv name
Suman
%
Note that the value of an environment variable is displayed without a $ prefix in the printenv command. Thus the printenv command displays the value of all currently defined environmental variables.
If you want to remove an environment variable definition then use the unsetenv command as:
% unsetenv name
Variable Modifiers
Variable modifiers are used to modify the interpretation of a regular shell variable. The C shell provides various variable modifiers. Some useful variable modifiers are listed below:
- :r it returns the variable’s root and remove a trailing extension
- :t it returns the variable tail and removes all leading pathnames.
- :e it returns the variable’s extension
- :h it returns the variable’s header
- :gr it returns all roots
- :ge it returns all extensions
- :gh it returns all headers
- :gt it returns all tails
You can used these variables modifiers by placing them at the end of a variable name. You can understand the significance of some of these variable modifiers as:
% set userfile = /usr/user2/project/report.txt% echo $userfile
/usr/user2/project/report.txt
% echo $userfile :r
/usr/user2/project/report
% echo $userfile :t
report.txt
% echo $userfile :e
txt
% echo $userfile :h
/usr/user2/project/
One should remember that never try to use these modifiers on environment variables.
Shell Script
As you have read in the Bourne shell that shell scripts are just shell programs having a sequence of commands in them. In other words, you can say that a shell script is a file of UNIX commands that tells the shell what to do.
A shell script also gives an elegant way to save and use a frequent combination of commands.
For example, if you want to display the list of all login users, followed by a list of all files in the current working directory then you would write a shell script as:
who
date
Let the name of this script is csscript1. Now you can run this script as:
% csh csscript1
Mon Oct 11 09:11:15 IST 1999
aa1 tty2 Oct 11 07:15
aa4 tty3a Oct 11 07:19
amit tty3d Oct 11 09:33
summy tty4 Oct 11 10:11
%
You can also execute it directly at command prompt as:
$ csscript1
But like Bourne shell, the default permission of a newly created file in C shell is 644 and it does not allow you to execute it. Therefore it is necessary to firstly change its file permissions as:
% chmod u+x csscript1or
% chmod 744 csscript1
and then you can use it at command prompt directly as:
% csscript1
Mon Oct 11 09:11:15 IST 2009
aa1 tty2 Oct 11 07:15
aa4 tty3a Oct 11 07:19
amit tty3d Oct 11 09:33
summy tty4 Oct 11 10:11
%
Note that here it is sh, not csh, which executes this later versions. No doubt it is due to the compatibility with the Bourne shell that executable shell scripts in the C shell are run by the sh unless the script begins with a # symbol. However in former case, that is
% csh csscript1
the shell script is run by the C shell. If you want to make the executable script a csh-run script then start it off with a comment as:
# C shell script1who
date
On contrary to this if you have a Bourne shell script with # markd comments then it is necessary either to remove the commands or run the script using sh as:
% sh anyscript
Now let us see another script in which we accept the input from the keyboard and display the output to the monitor. We all know that the Boune shell provides a read command to receive input from the standard input. Unfortunately the C shell does not provide any such command. The C shell provides $< to indicate that the input is to be taken form the shell’s standard input.
Like Bourne shell, the C shell uses echo command to display the information.
# C shell script2# Usage: csscript2
echo What is your name\?
set name=$<
echo What is your age\?
set age=$<
echo Hello $name. You are $age years old.
Like csscript1, csscript2 too has the default permissions 644. So firstly change its file permissions to 744 and execute it at the shell prompt as:
% csscript2What is your name?
Shrey
What is you age?
2
Hello Shrey. You are 2 years old.
%
I know that you must have noticed the ‘\’ just before the question mark ‘?’ at the end of first and second echo statement in the csscript2. It is because we all know that the ‘?’ symbol is metacharacter which if not preceded by a ‘\’ represents for all files in the current working directory whose names are one character long. If you want to treat the symbol ‘?’ as an ordinary character then it is necessary to precede it by a backslash as ‘\’.
Command Line Substitution
The C shell provides the shell variable argv in which it stores the command line arguments of a shell script. For example, the parameter
$#argv
represents the total number of arguments. If you have multiple arguments then you can access the separate arguments by using the break notation. Let you have 10 arguments at command line and want to access the 5th argument then you must type
$argv[5]
Following shell script illustrates this concept.
# C shell script3# Usage: csscript3
echo Total number of arguments $#argv
echo The first argument is $argv[1]
echo The last argument is $argv[$#argv]
echo The first through fifth argument is $argv[1-5]
echo The sixth through tenth argument is $argv[6-10]
Make this script executable and run it as:
% csscript3 Imagination is useful only as long as it remains practical.Total number of arguments 10
The first argument is Imagination
The last argument is practical.
The first through fifth argument is Imagination is useful only as
The sixth through tenth argument is long as it remains p.
%
To preserve compatibility with the Bourne shell, you can also use $1, $2, $3,…and so on, notation of the Bourne shell in the C shell. Therefore, $1 is equivalent to $argv[1], $2 is equivalent to $argv[2], and so on. On the same track, $* is the same as $argv[*]
Let us see some other useful command line parameters.
$0 the name of the shell script
$$ process number of current shell
$?num returns if num is set; 0 if num is not set
$status returns the status of the last command
$< reads a line from standard input
$?0 returns 1 if input filename is known; 0 if not
C Shell Metacharacters
Shell metacharacters are special characters to which special meaning has been assigned by the UNIX system. The details of these shell metacharacters are already discussed in Bourne shell.
Here we will only summarize them.
Filename Expansion Metacharacters
- ? match any one character
- * match any combination of characters (including the null character and excluding an initial period)
- [list] match any one character from the list
- [!list] match any one character except those enclosed in the lsit
Special Shell Metacharacters
- $# total number of positional parameters
- $0 name of the command being executed
- $* list of all shell arguments
- $@ same as $*, but yields each argument separately when enclosed in double quotes
- $! Process ID of the last background command
- $$ Process ID of the current command
- $- current shell setting
- $? The exit status of last executed command
Now we will see – how the expressions are evaluated in C shell
Expressions
The C shell expressions involve operators and operands just like C language. The value of an expression can be assigned to a shell variable via the @ command. The @ command allows you to perform you to perform numerical manipulations in the expression.
The @ command is similar to the set command, except it assigns the value of an expression rather than a word to a variable. It means that you can not assign a word to a shell variable by using the @ command. The C shell provides five arithmetic operators:
Arithmetic Operators
Symbols Meaning
* / % Multiplication, integer division, remainder
+ – Addition, subtraction
Now let us see some simple shell programs.
# C shell script4# Usage: csscript4
set name = Shery
@ age = 24
@ salary = 100000
echo $name $age $salary
When you execute this script, you get the following output….
% csscript4
Shrey 24 100000
%
Now let us write a script that displays the reverse of a five digit number.
# C shell script5# Usage: csscript5
echo “Enter a number: \c”
set n = $<
@ a = n % 10
@ n = n / 10
@ b = n % 10
@ n = n / 10
@ c = n % 10
@ n = n / 10
@ d = n % 10
@ n = n / 10
@ e = n % 10
@ rev = a * 10000 + b * 1000 + c * 100 + d * 10 + e
echo The reverse of a five digit number is: $num
The output of this program is….
% csscript5
Enter a number: 12345
The reverse of a five digit number is: 54321
%
The C shell also provides the increment operator (++) and decrement operator (--) of C language.
Following program illustrates the behavior of these two operators.
# C shell script6# Usage: csscript6
@ a = 20
@ b = 10
@ a++
@ b- -
echo $a $b
@ a++
@ b- -
echo $a $b
And here is the output of this script….
% csscript6
21 9
22 8
%
Assignment Operators
The C shell provides following types of assignment operators.
Symbol Meaning
= Assigning value
+= -= Reassign after addition/subtraction
*= /= %= Reassign after multiplication/division/remainder
On the similar track you can use arithmetical assignment operators as:
# C shell script7# Usage: csscript7
@ a = 20
@ b = 10
@ a += b
echo $a
@ b -= 4
echo $b
@ a *= b
echo $a
@ a /= 9
echo $a
@ a %= 3
echo $a
The output of this script is as….
% ssscript7
30
6
180
20
2
%
Like Bourne shell, the C shell also provides programming constructs, such as if – else, the while loop, the foreach loop, and the repeat loop.
The if Structure
We know that, the instructions in a program are executed sequentially. But sometimes we need to do one thing under some circumstances and a different thing otherwise. To accomplish this, the C shell provides the if structures to control the order of execution of the commands in the program. Let us begin with the simple if structure.
The simplest form of if command is
if (expression) command
Here unlike the Bourne shell’s if, the expression is enclosed within parentheses. If the result of expression is true then the command is executed; otherwise not. And the command must be a simple and single command. You can not use pipes and compound commands.
If you want to use several commands then the C shell provides the if–then-endif structure. Its syntax is
if (expression) thencommand1
command2
….
endif
Here if the expression results in true, the commands enclosed between the keyword then and endif are executed. It is necessary to place the if – then portion on one line, the endif on another line and the set of commands in between these two lines.
Let us see how to use this structure.
# C shell script8# Usage: csscript8
echo What is your age\?
set age = $<
if ($age <= 20) then
echo You have not yet grown up.
echo Please take a ThumsUP.
endif
A sample run of this script is….
% csscript8What is your age?
16
You have not yet grown up.
Please take a ThumsUP.
%
Here we have seen that if the expression results in true, the if statement executes a command or a set of commands. It does nothing when the expression is false. If you want to perform something even when the expression results in false, then you can use another form of if structure, that is if-then-else-endif.
Here is the general form of this if structure
if (expression) thencommand
command
….
else
command
command
….
endif
Let us rewrite csscript8 in which we include the else part.
# C shell script9# Usage: csscript9
echo What is your age\?
set age = $<
if ($age <= 20) then
echo You have not yet grown up.
echo Please take a cold drink.
else
echo You can drink Beer.
endif
A sample run of this script is….
% csscript9
What is your age?
16
You have not yet grown up.
Please take a cold dring..
% sscript9
What is your age?
22
You can drink Beer.
%
Nested if–elses Structure
Like C language, the C shell also provides the facility of using nested ifs, that is defining if-then-else-endif structure within either the if body or the else body.
The syntax of nesting if structure is
if(expression1) thenif (expression2) then
command1
command2
else
command3
command4
endif
else
command5
command6
endif
or
if(expression1) then
command1
command2
else
if (expression2) then
command3
command4
else
command5
command6
endif
endif
In the former case, the second if structure is nested in the first if statement whereas in later form, the second if structure is nested in the first else statement. Note that there is no limit on how deeply the ifs and elses can be nested.
Following program illustrates the usage of nested ifs.
# C shell script10# Usage: csscript10
echo What is your age\?
set age = $>
if ($age <= 5) then
echo You are a lovely kid.
else
if ($age >5 && $age <= 10) then
echo You are growing up.
else
if ($age >10 && $age <= 20) then
echo You have not yet grown up.
else
echo Nice to see a young guy.
endif
endif
endif
Here you have used logical && operator to combine two condition into one.
The output of this program is
% csscript10
What is your age?
23
Nice to see a young guy.
% csscript10
What is your age?
13
You have not yet grown up.
% csscript10
What is your age?
4
You are a lovely kid.
%
Here we have used multiple endifs. You can also avoid typing multiple endifs by typing else if on just one line as shown below:
# C shell script11# Usage: csscript11
echo What is your age\?
set age = $<
if ($age <= 5) then
echo You are a lovely kid.
else if ($age >5 && $age <= 10) then
echo You are growing up.
else if ($age >10 && $age <= 20) then
echo You have not yet grown up.
else
echo Nice to see a young guy.
endif
The output of this shell program is similar to csscript10.
Thus nested if-elses offers two or more choices. Here if the first expression is true then the if block is executed and control reaches the endif. If the first expression is false then the control goes to the first else-if block. In this again the expression is evaluated. If it is true then the command following it is executed otherwise the control reaches at next else-if. This process continues for other elseifs. If all the expressions are false then the control reaches the else block and executes the command(s) within it.
File Testing Expressions
Like Bourne shell, the C shell also provides several options for checking the status of a file. These are listed as:
-r file true if file exist and is readable
-w file true if file exist and is writeable
-x file true if file exist and is executable
-f file true if file exist and not a directory
-d file true if file exist and is a directory
-c file true if file exist and is a character special file
-b file true if file exist and is a block special file
-s file true if file exist and has a size greater than 0
-k file true if file exist and its sticky bit is set
With the help of these options, you can easily find out whether the specified file is an ordinary file, a directory or whether it grants read, write or execute permissions and so on.
Here is a more concrete example.
# C shell script12# Usage: csscript12
echo “Enter a filename: \c”
set filename = $<
if ( -d $filename) then
echo This is an ordinary file.
else if ( -f $filename)
echo This file is a directory file.
else
echo What did you enter\?
endif
On executing this script, you get the following output….
% csscript12Enter a filename: bin
This file is a directory file.
% csscript12
Enter a filename: Jana
What did you enter?
%
The switch Structure
No doubt, nested ifs may offer multiple choices. But it is the switch structure that offers an efficient way to compare a value to a list of choice and to take the corresponding action. The behavior of the switch structure is similar to the case structure of the Bourne shell.
The general form of the switch structure is
switch (value)
case choice1 :
command
command
….
breaksw
case choice2 :
command
command
….
breaksw
case choice3 :
command
command
….
breaksw
default :
command
command
….
breaksw
endsw
The syntax of the switch structure closely looks like the switch of the C language.
Here the value is matched with successive case labels (choice1, choice2 and so on) until it finds a match. Whenever it finds a match, it executes the commands belong to that particular case label. If there is no match, the program executes the commands of the default label. Here the keyword breaksw is used to take control out of switch structure as soon as it executes all the commands from that match label. If you don’t use the breaksw the all the commands from that matching label to endsw are executed.
Let us now put these concepts to a practical stint. Here is the program that illustrates the usage of the switch structure.
# C shell script13# Usage: csscript13
echo “Enter a character from a to d : \c”
set char = $<
switch ($char)
case a: echo You have entered a.
breaksw
case b: echo You have entered b.
breaksw
case c: echo You have entered c.
breaksw
case d: echo You have entered d.
breaksw
default: echo Please enter a to d.
breaksw
endsw
Here the program asks the user to enter a character and then determines whether you have entered a, b, c, d or something else.
The output of this program is….
% csscript13Enter a character from a to d : a
You have entered a.
% csscript13
Enter a character from a to d : d
You have entered d.
% csscript13
Enter a character from a to d : g
Please enter a to d.
%
Note that the case labels may be in any order you want. You can place case label b before a, d before b, or in any order. Here is the example of scrambled case order.
# C shell script14# Usage: csscript14
echo “Enter a character from a to d : \c”
set char = $<
switch ($char)
case b: echo You have entered b.
breaksw
case d: echo You have entered d.
breaksw
case c: echo You have entered c.
breaksw
case a: echo You have entered a.
breaksw
default: echo Please enter a to d.
breaksw
endsw
The output of this program is similar to earlier one.
However you are not limited to using single letters or digits. You can also use entire words as the choice labels as shown in following script.
# C shell script15# Usage: csscript15
echo “Enter any cricketer name: \c”
set name = $<
switch ($name)
case Sachin: echo Best Batsman
breaksw
case McGrath: echo Best Bowler
breaksw
case Gilchrist: echo Best Wicket Kepper
breaksw
case Cairns: echo Best All Rounder
breaksw
case Rhodes: echo Best Fielder
breaksw
default: echo Your taste is different.
breaksw
endsw
Here is some interaction with the program….
% csscript15Enter any cricketer name: McGrath
Best Bowler
% csscript15Enter any cricketer name: Sachin
Best Batsman
% csscript15
Enter any cricketer name: Rhodes
Best Fielder
% csscript15Enter any cricketer name: Cronje
Your taste is different.
%
One more point to note, while suing the switch structure, that makes the default choice as the last choice. If you make it as the first choice then it would match any value and the case would not be searched any further.
If you want to know about some other options please study the Bourne shell case structure.
Logical Operators
Like Bourne shell, the C shell provides following three types of logical operators:
Symbol Meaning
&& AND
|| OR
! NOT
First two operators, && and ||, allow two or more conditions in a single condition. Now let us write a script that determines whether a year is a leap or not, with the help of logical && and || operators.
# C shell script16# Usage: csscript16
echo “Enter any year: \c”
set year = $>
if (($year%4==0)&&($year%100!=0)||($year%400==0)) then
echo $year is a leap year.
else
echo $year is not a leap year.
Here is the simple interaction with the program….
% sccript16Enter any year: 1976
1976 is a leap year.
% sccript16
Enter any year: 1900
1976 is not a leap year.
%