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.
%
Loops
Like Bourne shell, the C shell also supports three loop structures
- The foreach loop
- The while loop
- The repeat loop
The foreach Loop
The general for of the foreach loop is as:
foreach shell_varaible (value1 value2 value3 …. )command1
command2
…. end
Here the loop control variable shell_varaible takes on in turn each value from the specified list of values and execute the same sequence of commands for each value. And this process continues until the list is emptied.
Here is the simple example of the foreach loop.
# C shell script17# Usage: csscript17
foreach day (MON TUE WED THU FRI SAT SUN)
echo $day
end
On executing this script, you get the following output….
% csscript17
MON
TUE
WED
THU
FRI
SAT
SUN
%
Here the loop control variable is day in turn takes the value in succession from the specified list (MON TUE WED THU FRI SAT SUN). Initially the day is set to ‘MON’ and the statements between foreach and end is executed. Then the day is set to next value ‘TUE’ and the echo statement is executed again.
As we have done indentation in the Bourne shell, likewise here also we have done indentation just to make it clearer to see where the loop starts and where it terminates.
Just like Bourne shell, the C shell has following techniques to provide wordlist:
- The foreach loop can take values from the shell script command line:
foreach name ($*)foreach name ($argv)
foreach name ($argv[1-5])
and so on. Recall that $* or $argv stands for command line arguments following the name of the script. The third foreach loop takes first five arguments and ignores the remaining arguments.
# C shell script18# Usage: csscript18
foreach name ($argv)
echo $name
end
Now let us see what happens when you execute this script.
% csscript18 Eyes are more accurate witness than ears.
Eyes
are
more
accurate
witness
than
ears.
%
Here the variable name takes in turn each command line argument and echo echoes its value.
- The foreach value can also take filenamesfrom a directory as values:
foreach fname (*)foreach fname (*.txt)
The first loop picks up all files from the current working directory; the second loop picks up all text files from the current working directory.
# C shell script19# Usage: csscript19
foreach filename (*)
mv $filename.txt $filename.doc
end
It would pick up all text files from current directory and make them document files
- The loop control variable can take values from a shell variable as shown below:
# C shell script20# Usage: csscript20
phrase = “Education begins with life”
foreach word ($phrase)
echo $word
end
When you execute this script, the foreach loop would become
foreach word (Education begins with life)
Here the control variable word would take values ‘Education’, ‘begins’, ‘with’ and ‘life’ in turn.
- The foreach loop can take values from the output of the command by using the back quotes ‘ ‘ command substitution as illustrated in following script.
# C shell script21# Usage: csscript21
foreach cm (‘ cat players ‘)
echo $cmd
end
Here the ‘ cat players ‘ would be replaced with the contents of file players and then the cmd would be set in turn each word in the file players.
The while Loop
The general form of the C shell is as:
while (expression)command
command
….
end
The commands within the while loop are executed till the expression results in true. When the expression becomes false, the control would automatically transfer to the first command that follows the while loop immediately.
Note that the commands within the while loop may be a single command or a set of commands. Unlike the Bourne shell, the expression is enclosed in parentheses. However there is a significant difference between the Bourne shell’s while and C shell’s while. In the Bourne shell’s while, the expression part is referred to the success or failure of command, whereas the C shell’s expression more typically is a comparison of value.
Now let us write a simple script that calculate the sum of first 50 odd numbers.
# C shell script22# Usage: csscript22
@ count=1
@ sum=0
while ( $count <= 50 )
@ sum = sum + 2 * count – 1
@ count++
end
echo The sum of first 50 odd numbers is $sum.
Here is the output of this script….
% csscript22
The sum of first 50 odd numbers is 2500
%
Here two commands are executed 50 times. Initially the variable count is set to 1 and sum to 0. In each iteration, the sum is evaluated, the value of count is incremented by one. As soon as the value of count becomes 51, the loop is terminated and the echo statement immediately echoes the value of sum.
Now let us write a program to find if a number is prime or not.
# C shell script23# Usage: csscript23
echo “Enter a number: \c”
set num = $<
@ i=2
@ flag = 1
while ($i <= $num / 2)
if ($num % $i == 0) then
@ flag = 0
break
endif
@ i++
end
if ($flag == 1) then
echo $num is a prime number.
else
echo $num is not a prime number.
endif
And here are few sample outputs….
% csscript23
Enter any number: 7
7 is a prime number.
% csscript23
Enter any number: 35
35 is not a prime number.
%
- In this program the loop continues until you type in other than a lower case ‘y’ or upper case ‘Y’. You have used the break command. The purpose of the break command in this shell is similar to the Bourne shell’s break command. It causes the loop to be exited.
- The switch statement, however, requires the use of breaksw rather than a break. The counter part of break is continue. The continue command causes the program to skip the remaining instructions in the loop and transfer the control to the beginning of the loop. Both these commands, break and continue, are associated with loops.
Now let us see another program that print even or odd numbers.
# C shell script24# Usage: csscript24
@ choice=y
while ($choice==y || $choice == Y)
echo “Enter a number: \c”
set num = $<
if ($num %2 == 0) then
echo “Even number”
else
echo “Odd number”
endif
echo “Do you want to continue \(y\n\): \c”
set $choice = $<
end
The output of this program is as….
% csscript24
Enter a number: 21
Odd number
Do you want to continue (y\n):y
Enter a number: 14
Even number
Do you want to continue (y\n):y
Enter a number: 200
Even number
Do you want to continue (y\n):n
%
All the operators of C shell are taken from the C language, except these two =~ and !~ operators. The =~ and !~ operators allow the right hand side to be a pattern using the filename metacharacters, *. ? & [ ] of the C shell.
Thus
=~ matches the string on the left side to the pattern containing *, ?. or [ ]
!~ matches the string on the left side to the pattern not containing *, ?. or [ ]
Following program illustrates such type of operators.
# C shell script25# Usage: csscript25
@ choice=y
while ($choice =~ [Yy])
echo “Enter a character: \c”
set char = $<
if ($char !~ [aeiou]) then
echo It is not a vowel
continue
else
echo It is a vowel.
Break
endif
end
The output of this program is….
% csscript25Enter a character: s
It is not a vowel
Enter a character: a
It is a vowel
%
Here the loop continues until the input matches with any character specified in the list [aeiou].
The repeat Loop
The C shell repeat loop looks like this:
repeat n command
Here the command is executed n times. The command must be a simple and single command. It may contain arguments and I/O redirection, but no pipes or set of commands.
Let us see the repeat command at command prompt.
% repeat 2 echo Great men never die.
Great men never die.
Great men never die.
%
You can also use this loop in a shell script. Here is the simple example.
# C shell script26# Usage: csscript26
echo “How many times you repeat this phrase\?”
phrase=”Glory is poison that can only be taken in small dosses.”
echo $phrase
set num = $<
repeat $num $phrase
When you execute this script, its output would be as….
% csscript26
How many times you repeat this phrase\?”
Glory is poison that can only be taken in small dosses.
4
Glory is poison that can only be taken in small dosses.
Glory is poison that can only be taken in small dosses.
Glory is poison that can only be taken in small dosses.
Glory is poison that can only be taken in small dosses.
%
Comparison of Bourne Shell and C Shell
Let us briefly summarize the differences between the Bourne shell and C shell.
|
ch |
csh |
Default Prompt |
$ |
% |
Comments |
# |
# |
Filename Expansion substitution |
? * [ ] [! ] |
? * [ ] [! ] |
System-defined Shell variables |
HOME PATH CDPATH TERM |
home path cdpath term |
I/O Redirection |
|
|
Log in files |
.profile |
.login
|
Variable Operations |
var=value var=’expr $var + 1‘ |
set var=value @ var=$var + 1 |
If statement |
if [test_expression] then Command(s) fi |
If (C_expression) then
Command(s) endif |
|
if [test_expression] then Command(s) else Command(s) fi |
if (C_expression) then
Command(s) else Command(s) endif |
|
if [test_expression] then Command(s) elif [test_expression] then Command(s) else Command(s) fi |
if (C_expression) then
Command(s) else if (C_expression) then Command(s) else Command(s) endif |
For Loop |
for var in list do Command(s) done |
foreach var (list)
Command(s) end |
While Loop |
while [test_expression] do Command(s) done |
while (C_expression)
Command(s) end |
Repeat-until Loop |
until [test_expression] do Command(s) done |
repeat n Command |
Switch-case Structure |
case value in label1) Commands(s) ;; label2) Commands(s) ;; *) Commands(s) ;; esac
|
switch (value) case choice1: Commands(s) breaksw case choice1: Commands(s) Breaksw default: Commands(s) breaksw endsw |
Transforming XML
The Purpose
The Client of the Client of the Client
It's Greek to Me
The Extensible Stylesheet Language (XSL)

How To Traverse XML
To begin this article, we take a look at how to make the transformations dangled in front of you throughout the last article actually occur on your own local machine. This should give you a "virtual playground" where you can experiment with all the various XSL and XSLT constructs on your own, as well as adding more complex formatting to the stylesheet we created last article. It mwill also begin our closer look into how an XSLT processor works. We then complement our view of a processor's output with a detailed look at the type of input it expects, and the format of this input. This leads us into a first look at the Document Object Model (DOM), an alternative to using SAX for getting to XML data. Finally, we will begin to move back a step from parsers, processors, and APIs, and look at how to put an XML application together. This will set the tone for the rest of the book, as we take a more topical approach on various types of XML applications and how to take advantage of proven design patterns and XML frameworks. Before going on, you should understand not only the focus of the article, but also what it does not focus on. This article will not teach you how to write an XSLT processor, any more than previous articles taught you to write an XML parser. Certainly the concepts here are very important, in fact critical, to using an XSLT processor, and are a great starting point for getting involved with existing efforts to enhance XSLT = processors, such as the Apache Group's Xalan processor. However, parsers and processors are extremely complex programs, and to try to explain the inner workings of them within these pages would consume the rest of this book and possibly another! Instead, we continue to take the approach of an application developer or Java architect; we use the excellent tools that are available, and enhance them when needed. In other words, you have to start somewhere, and for a Java developer, using a processor should precede trying to code one.
Getting the Output
If you followed along with our examples in the last article, you should be ready to put your stylesheet and XML document through a processor and see the output for yourself. This is a fairly straightforward process with most XSLT processors. Continuing in our vein of using open source, best-of-breed products, we will use the Apache Xalan XSLT processor, which you can find information. In addition to being contributed to by Lotus, IBM, Sun, Oracle, and some of the best open source minds in the business, Xalan fits in very well with Apache Xerces, the parser we looked at in earlier articles. If you already have another processor, you should easily be able to find the programs and instructions needed to run the examples in this article; your output should also be identical or very close to the example output we look at here.
The first use of an XSLT processor we will investigate is invoking it from a command line. This is often done for debugging, testing, and offline development of content. Consider that many highperformance web sites generate their content offline, often nightly or weekly, to reduce the load and performance constraints of dynamically transforming XML into HTML or other markup languages when a user requests a page. We can also use this as a starting point for peeling back the layers of an XML transformation. Consult your processor's documentation for how to use XSLT from the command line. For Apache Xalan, the command used to perform this task is:
D:\prod\JavaXML> java org.apache.xalan.xslt.Process
-IN [XML Document]
-XSL [XSL Stylesheet]
-OUT [Output Filename]
Xalan, like any processor you choose, can take in many other command-line options, but these three are the primary ones we want to use. Xalan also uses the Xerces parser by default, so you will need to have both the parser and processor classes in your class path to run Xalan from the command line. You can specify a different XML parser implementation through the command line if you wish, although the support for Xerces is more advanced than for other parsers. You also do not need to reference a stylesheet in your XML document if generating a transformation this way; the XSLT processor will apply the stylesheet you specify on the command line to the XML document. We will use our XML document's internal stylesheet declarations. So taking the names of our XML document and XSL stylesheet (in this case in a subdirectory), we can determine the syntax needed to run the processor. Since we are transforming our XML into HTML, we specify contents.html as the output for the transformation:
D:\prod\JavaXML> java org.apache.xalan.xslt.Process
-IN contents.xml
-XSL XSL/JavaXML.html.xsl
-OUT contents.html
Running this command from the appropriate directory should cause Xalan to begin the transformation process, giving you output similar to that shown in Example (a).
Example (a) . Transforming XML with Apache Xalan
D:\prod\JavaXML>java org.apache.xalan.xslt.Process
-IN contents.xml
-XSL XSL/JavaXML.html.xsl
-OUT contents.html
========= Parsing file:D:/prod/JavaXML/XSL/JavaXML.html.xsl ==========
Parse of file:D:/prod/JavaXML/XSL/JavaXML.html.xsl took 1161 milliseconds
========= Parsing contents.xml ==========
Parse of contents.xml took 311 milliseconds
=============================
Transforming...
transform took 300 milliseconds
XSLProcessor: done
Once this is complete, you should be able to open the generated file, contents.html, in an editor or web browser. If you followed along with all the examples in the last article, your HTML document should look similar to Figure (b).
Figure(b) . HTML from XML transformation
As simple as that, you have a means to make changes and test the resultant output from XML and XSL stylesheets! The Xalan processor, when run from the command line, also has the helpful feature of identifying errors that may occur in your XML or XSL and the line numbers on which those errors are encountered in the source documents, aiding even further in testing and debugging.
Getting the Input
Besides the reasons already mentioned for not going into how a processor works, there is an even better reason not to spend time on the issue: the inputs and outputs of the processor are far more interesting! You have seen how to parse a document incrementally with the SAX interfaces and classes. You can easily make decisions within the process about what to do with the elements encountered, how to handle particular attributes, and what actions error conditions should result in. However, there are some problems with using that model in various situations, and providing input to an XSLT processor is one of them.
SAX Is Sequential
The sequential model that SAX provides does not allow for random access to an XML document. In other words, in SAX you get information about the XML document as the parser does, and lose that information when the parser does. When element 2 comes along, it cannot access information in element 4, because element 4 hasn't been parsed yet. When element 4 comes along, it can't "look back" on element 2. Certainly, you have every right to save the information encountered as the process moves along; coding all these special cases can be very tricky, though. The other more extreme option is to build an in-memory representation of the XML document. We will see in a moment that a Document Object Model parser does exactly that for us, so performing the same task in SAX would be pointless, and probably slower and more difficult.
SAX Siblings
Another difficult task to achieve with the SAX model is moving laterally between elements. The access provided in SAX is largely hierarchical, as well as sequential. You are going to reach leaf nodes of the first element, then move back up the tree, then down again to leaf nodes of the second element, and so on. At no point is there any clear relation of what "level" of the hierarchy you are at. Although this can be implemented with some clever counters, it is not what SAX is designed for. There is no concept of a sibling element; no concept of the next element at the same level, or of which elements are nested within which other elements. The problem with this lack of information is that an XSLT processor must be able to determine the siblings of an element, and more importantly, the children of an element. Here, templates are being applied via the xsl:apply-templates construct, but they are being applied to a specific node set that matches the given XPath expression. In this example, the template should be applied only to the elements myChildElement1 or myChildElement2 (separated by the XPath OR operator, the pipe). In addition, because a relative path is used, these must be direct children of the element myParentElement. Determining and locating these nodes with a SAX representation of an XML document would be extremely difficult. With an in-memory, hierarchical representation of the XML document, locating these nodes is trivial, another reason why the DO approach is heavily used for input into XSLT processors.
Why Use SAX At All?
All these discussions about the "shortcomings" of SAX may have you wondering why one would ever choose to use SAX at all. If you are thinking along these lines, remind yourself that these shortcomings are all in regard to a specific application of XML data, in this case processing it through XSL. In fact, all of these "problems" with using SAX are the exact reason you would choose to use SAX. Confusing? Maybe not as much as you think. Imagine parsing a table of contents represented in XML for an issue of National Geographic. This document could easily be 500 lines in length, more if there is a lot of content within the issue. Imagine an XML index for an O'Reilly book. Hundreds of words, with page numbers, crossreferences, and more. And these are all fairly small, concise applications of XML. As an XML document grows in size, so does the in-memory representation when represented by a DOM tree. Imagine an XML document so large and with so many nestings that the representation of it using the DOM begins to affect the performance of your application. And now imagine that the same results could be obtained by parsing the same input document sequentially using SAX, and only need one-tenth, or one-hundredth, of your system's resources to accomplish the task. The point of this example is that just as in Java there are many ways to do the same job, there are many ways to obtain the data in an XML document. In various scenarios, SAX is easily the better choice for quick, less-intensive parsing and processing. In other cases, the DOM provides an easyto- use, clean interface to data in a desirable format. You, the developer, must always analyze your application and its purpose to make the correct decision as to which method to use, or how to use both in concert. As always, the power to make good or bad decisions lies in your knowledge of the alternatives. Keeping that in mind, let's look at this new alternative in more detail.
The Programming Style
In earlier section we saw that how a flowchart is evolved to solve a problem. The flowchart is just an aid to the programmer to plan his strategy to solve a problem A computer can not directly interpret it. A computer can interpret it only if it is coded into low-level language (machine or assembly) or high-level language. Unfortunately it is not always possible to write complex programs in low-level language. Therefore computer programs may be written in a into high-level language. The concept of programming involves more than simply writing a program. In addition, using meaningful names to variables and functions, documentation and maintenance of programs are important parts of programming.
Documentation
Documentation is just a written text and comments that make a program easier for others to understand, use and modify. Documentation should be kept up to date. Any change made in the program should be marked in all of the pertinent documentation. As far as small programs are concerned you indeed can keep all the details in your head, and so needs documentation only to explain the program to someone else. But as far as large and complex programs are concerned it becomes impossible to remember how every detail relates each other and therefore, it is essential that appropriate documentation be prepared along with each small part of the program. Thus the important point is that keep your documentation concise but descriptive.
Spaces, blank lines, and indentation in a program are an important form of documentation. These white space characters make the program easy to read, allow you to tell at a glance which parts of the program relate to each other, which statements are contained in which loop, and so on. In other words, you can say that using white space characters, it is easier to determine the structure of the program.
Once a program is fully debugged and in use, it is necessary to maintain it. Maintenance of programs is the modification of programs needed to meet new requests after they have been completed.
Naming Variables and Functions
While writing a program, one should give meaningful names to variables and functions so that their places in the program can be properly recognized and appreciated. Although finding good names is not an easy task, the careful choice of names go a long way in clarifying a program and in helping to avoid common errors. Let us see what should be kept in mind while selecting names.
- Use the meaningful names for variables, constants and functions such that they should suggest clearly the purpose of variables and functions.
- Use a single letter for the variable controlling a loop.
- Use common prefixes or suffixes to associate names to variables and functions as:
ReadArray
DisplayArray
InsertElement
DeleteElement
- Don’t use misspelling and meaningless suffices to the variables.
- Don’t choose names that are close to the each other in spelling or otherwise be ready to confuse.
Debugging of Programs
The process of detecting and removing errors in a program is referred as program testing and debugging. No body is perfect, at least I am not. When we code the algorithm then it is not necessary that our program should be 100 percent error–free. It means that there may occur any type of errors in the program. And it is totally programmer’s duty to trace out such errors and correct them that are likely to be present in the program.
There are four basic types of errors:
- Syntax errors
- Run–time errors
- Logical errors
- Latent errors
Syntax Errors
Every programming language has its own set of rules and the errors, which violate such rules, are referred as syntax errors. Fortunately syntax errors are immediately detected and isolated by the compiler during compilation purpose. The compilation phase of the program would not be completed until any syntax error is present in the program.
Following are the example of some syntax errors:
- int area-square, radius-of-circle; /* no hyphen */
- float 10salary; /* starts with a number sign */
- char @basic /* starts with a @ sign */
Normally the compiler specifies the line number where the error has occurred. But in some cases, the line number may not exactly indicate the place of error. So you have to find out that place.
Run–Time Errors
The errors, which occur during the runtime of a program, are referred as run–time errors or execution–time errors. Generally run–time errors come when there is any mismatch of basic data types or make an illegal reference and so on.
Logical Errors
The errors, which are directly related to the logic of the program, are referred as logical errors. Logical errors occurs due to wrong jumping, failure to satisfy a particular condition, and any incorrect order of evaluation of statements. Like run–time errors, the logical errors are not recognized by the compiler.
Following are the examples of some logical errors:
- if (i=1)
{
stat1;
stat2;
}
Here instead of using logical equal to (==) operator we have used assignment operator (=). A test condition, like this, would always be result in true.
2. if (num==sum)
printf (“Both are equal”);
If ‘num’ and ‘sum’ are float types values, then it is not necessary to become equal due to truncation error. Generally such type of errors occur due to incorrect coding of the algorithm.
Latent Errors
The errors that come in existence when we enter some special values during the execution of a program are called as latent errors. Consider the following statements:
1. a = 1 / b;
In this statement an error occurs only when b is equal to 0.
2. x = 4 + c / (a-b);
Here an error occurs when ‘a’ and ‘b’ are equal.
Latent errors can be detected only by using all possible combination of test data.
Program Testing
Program testing is the process of running the program on sample data chosen to find errors, if they are present, before the program is used on actual data. Earlier we have discussed that the compiler can detect only the syntactic and semantics errors. All other errors can be traced out at run time only. Therefore it is necessary for the programmers to detect all such errors by taking some realistic data.
One of the most effective way to find errors is called a structured walkthrough. You can also call it as human testing. In this the programmer shows the complete source code to another programmer or a peer group. Structured walkthrough is carried out statement by statement by the programmer and is analyzed with respect to a checklist of common errors.
The testing should be done initially on function level and when all goes well then it should be made on the complete program level. When we talk about the program testing, it is also necessary to point out the quality of test data. The quality of test data should be selected in the following ways:
- Easy values – The program is tested with data that are easy to check; otherwise the complicated data may embarrass the programmer.
- Typical Realistic value – The testing data should be simple realistic so that the result can be checked by hand.
- Extreme values – Testing should be done at the limits of his range of application.
- Illegal values – The program should also be tested for some illegal values so that it becomes able to produce a sensible error message.
The ultimate conclusion is that program testing can be used to show the presence of errors but never their absence.
More Articles …
Page 8 of 13