Training, Open Source computer languages

PerlPHPPythonMySQLhttpd / TomcatTclRubyJavaC and C++LinuxCSS

Search our site for:
Home Accessibility Courses Diary The Mouth Forum Resources Site Map About Us Contact
 
For 2023 (and 2024 ...) - we are now fully retired from IT training.
We have made many, many friends over 25 years of teaching about Python, Tcl, Perl, PHP, Lua, Java, C and C++ - and MySQL, Linux and Solaris/SunOS too. Our training notes are now very much out of date, but due to upward compatability most of our examples remain operational and even relevant ad you are welcome to make us if them "as seen" and at your own risk.

Lisa and I (Graham) now live in what was our training centre in Melksham - happy to meet with former delegates here - but do check ahead before coming round. We are far from inactive - rather, enjoying the times that we are retired but still healthy enough in mind and body to be active!

I am also active in many other area and still look after a lot of web sites - you can find an index ((here))
Korn Shell - Interactive and Programming basics

What is a Shell Program / Script?

A Shell is a program which reads user inputs and controls program output - a command line interpretter. Instructions typed in are split down into component parts (tokenized) and acted on accordingly - typically with the computer's underlting operating system running one or more programs or commands, and returning the output of those programs as described within the instruction.

The term "Shell" is typically used in the Unix and Linux world - a DOS command line interpretter is the near equivalent for Windows.

Where you have a requirement to rerun the same series of commands on a Unix / Linux system, you can save your commands / instructions into a file and then perform the file as a whole - and that is commonly known as a "Shell Script" or "Shell Program".

All mainstream programming languages include conditional constructs (to allow the programmer to specify code which may or may not be performed depending on the result of a test), loops (to allow a specific piece of code to be repeatedly executed a number of times without it having to be repeated in the program), variables (to allow information to be stored within the program from one operation through to following ones) and functions (to allow a piece of code that's required multiple times to be called up by a single easy name whenever it's needed). Shells are no exception - they include conditionals, loops, variables, and functions.

Why are there several different shells available?

The original shell - knows as the Bourne Shell - is found in a file called "sh". Dating back many years now, to the days of printing terminals and batch computing, it was (and is) very strong on programming facilities compared to facilities that are really needed for good command line interaction. The Bourne shell remains the bedrock of Unix and Linux systems, with the operating system's internal scripts that are run at startup and shutdown time programmed in "sh".

In order to provide better interaction, The C Shell was developed and this provided far greater interaction facilities - for example, the ability to rerun a previous command which is something that is exceedingly useful on the command line, but pretty much unwanted in batch files. The C Shell was adopted as the standard for many users, especially on Unix varients such as SunOS / Solaris.

In order to make the best of both worlds, the Korn Shell (ksh) was developed. Compatible with the Bourne Shell, but adding to it the intercative capabiities (all be it with a different syntax) of the C shell, it was / is intended to provide the best of both worlds.

And there are other shells you'll come across too - ranging from "bash" - the bourne again shell - which is very popular on Linux systems, through tcsh (an open source varient of the C shell) right up the alphabet to zsh. You may also see reference to the pdksh - the public domain Korn shell - which is in practise the flavour used in Linux.

Some exceptions to the "just another shell" rule - note that rsh and ssh are remote shell commands / protocols - not really shells in their own rights, but mechanisms through which shells can be accessed via a network. Rsh allows you to run a command on a remote server, and the ssh program allows you to conatct one machine from a nother on a network, and run commands remotely with the traffic between the two hosts being encrypted to stop intermediate snooping.

Korn Shell Basics

-* Each instruction starts with the name of the command (which may be something that's built in to the shell, or a separate operating system command).

-* Instructions are followed, optionally, by a number of parameters which are separated from one another by white space

-* Instructions are terminated by a new line character.

Example:

$ grep -c public Temperatures.java WellHouseInput.java
Temperatures.java:2
WellHouseInput.java:6
$

The instruction is a seperate command called "grep" in this case, and it has four parameters. The first is "-c, the second is "public", the third is "Temperatures.java" and the fourth is "WellHouseInput.java". When run on the machine these notes were written on, you'll see that we typed the command against as shell prompt "$" character, and it produced two lines of output.

Metacharacters

As well as tokenising and passing through commands, shells support a number of metacharacters which effect how they do that parsing and what they do as they run commands.

PIPING AND REDIRECTION

> redirects the output from a command (on what is known as STDOUT or the regular job output) to a file named thereafter. If the file already exists, the prior contents are cleared out first.

>> redirects the output from a command (on what is known as STDOUT or the regular job output) to a file named thereafter. If the file already exists, new contents are added on to the end

< redirects the input to a command (know as STDIN or the regular input) from the named file rather than from the keyboard.

| diverts the STDOUT of one command in to the STDIN channel of the next one, thus making a production line of commands.

$ ls .. > first
$ date > second
$ ls .. >> second
$ cat -n second | more
     1 Sat Sep 22 07:11:39 BST 2007
     2 ABC
     3 abc.html
     4 ac_20060330.xyz
     5 ac_20060331.xyz
     6 ac_20070123.xyz
(etc)
$ cat -n < first
     1 ABC
     2 abc.html
     3 ac_20060330.xyz
     4 ac_20060331.xyz
     5 ac_20070123.xyz

As well as STDOUT, commands have a second output channel known as STDERR which is used for error messages. The idea of STDERR being separate is that you can direct the regular output to a file for later use, but still see the error messages on the screen. In the Korn shell, you can divert STDERR too using 2>.

$ ls sfdsdf
ls: sfdsdf: No such file or directory
$ ls sdfsdf > demo
ls: sdfsdf: No such file or directory
$ ls hjsdfhj 2> demo
$ cat demo
ls: hjsdfhj: No such file or directory
$ ls / wobble > head 2> body
$ cat head
/:
bin
boot
dev

etc

$ cat body
ls: wobble: No such file or directory
$

You can also combine STDOUT and STDERR to the same file using 2>&1. Doing two separate diverts to the same file will NOT work, as one output overrides the other.

$ ls / wobble > hh 2>&1
$ ls / wobble > ii 2> ii
$ diff ii hh
0a1
> ls: wobble: No such file or directory
$

Other combined uses ... you'll often pipe, pipe, pipe, pipe, redirect.

Example:

$ gzip -dc /usr/share/man/man1/ksh.1.gz | groff -T html > ksh.html
$ ls -l
total 168
-rw-r--r-- 1 trainee users 38 2007-09-22 07:21 body
-rw-r--r-- 1 trainee users 39 2007-09-22 07:18 demo
-rw-r--r-- 1 trainee users 2643 2007-09-22 07:11 first
-rw-r--r-- 1 trainee users 101 2007-09-22 07:21 head
-rw-r--r-- 1 trainee users 139 2007-09-22 07:22 hh
-rw-r--r-- 1 trainee users 101 2007-09-22 07:24 ii
-rw-r--r-- 1 trainee users 136357 2007-09-22 07:36 ksh.html
-rw-r--r-- 1 trainee users 2672 2007-09-22 07:11 second

WILD CARDS

If you write *.txt to match all the file names that end in .txt, it's actually the shell that's doing the work and providing the extra parameters. You can see this in the Korn shell by doing a set -x, then using a wildcard:

$ set -x
$ ls -l *.*
+ ls -l ksh.html ksh.txt
-rw-r--r-- 1 trainee users 1150 2007-09-22 07:47 ksh.html
-rw-r--r-- 1 trainee users 127555 2007-09-22 07:45 ksh.txt
$

This means that you can use the following wildcards to match EXISTING FILE NAMES ONLY (different to Windows Wild cards)

- MATCH 0 OR MORE CHARACTERS
? - match any one character [xyz] - match one character from the list ~ - shorthand for your home directory ~fred - shorthand for fred's home directory.

Note that a range [a-z] is allowed, as is a ! for not - [!aeiou]

Other Korn shell "Wild cards" are:

 @(...|...) - match one occurrence of any option
 +(...|...) - match one or more occurrences of any option
 *(...|...) - match zero or more occurrences of any option
 ?(...|...) - match zero or one occurrence of any option
 !(...|...) - match anything that does NOT include any option

Examples:

+ ls
body demo first head hh ii ksh.html ksh.txt second
$ ls +(ks|he)*
+ ls head ksh.html ksh.txt
head ksh.html ksh.txt
$ ls !(hh|ii)
+ ls body demo first head ksh.html ksh.txt second
body demo first head ksh.html ksh.txt second
$

Although not REALLY wildcards, don't forget . and .. for "current directory" and "parent directory" respectively.

As with all Unix and Linux shells, you must NOT try to use these wild cards to create new file names.

QUOTING

If you enclose part of your command line in ' characters, you're saying that you wantit taken as a single parameter. Using " characters instead is similar, but allows any shell variable mentioned within to be expanded. And a \ character removes the special significance from just the following character.

$ cat peter john glover
cat: peter: No such file or directory
cat: john: No such file or directory
cat: glover: No such file or directory
$ cat "peter john glover"
cat: peter john glover: No such file or directory
$ cat 'peter john glover'
cat: peter john glover: No such file or directory
$ cat peter\ john glover
cat: peter john: No such file or directory
cat: glover: No such file or directory
$

If you use BACKQUOTES, you're doing the opposite of protecting a part of your command line - you're isntructing the shell to perform the contents before it performs the rest of the command, and substitute the information in place. Thus

$ date +%A
Saturday
$ ls > `date +%A`.txt
$ ls -l Sat*
-rw-r--r-- 1 trainee users 64 2007-09-22 09:26 Saturday.txt
$

CONTINUATION AND SPLITTING A LINE

You may specify several commands on one line, separating them with a ; characted, and you may use a \ to continue on form one line to another.

$ ls \
> -l
total 168
-rw-r--r-- 1 trainee users 38 2007-09-22 07:21 body
-rw-r--r-- 1 trainee users 39 2007-09-22 07:18 demo
-rw-r--r-- 1 trainee users 2643 2007-09-22 07:11 first
-rw-r--r-- 1 trainee users 101 2007-09-22 07:21 head
-rw-r--r-- 1 trainee users 139 2007-09-22 07:22 hh
-rw-r--r-- 1 trainee users 101 2007-09-22 07:24 ii
-rw-r--r-- 1 trainee users 1150 2007-09-22 07:47 ksh.html
-rw-r--r-- 1 trainee users 127555 2007-09-22 07:45 ksh.txt
-rw-r--r-- 1 trainee users 64 2007-09-22 09:26 Saturday.txt
-rw-r--r-- 1 trainee users 2672 2007-09-22 07:11 second
$ pwd ; ls
/home/trainee/korn
body demo first head hh ii ksh.html ksh.txt Saturday.txt second
$

ENVIRONMENT VARIABLES

When you start a new shell, you're provided with a number of "shell variables" - named memory locations with values relating to the current shell set in them.

You may use them within your commands by preceeding them with a $.

You may set them using an "=" assignment - NO DOLLAR is this case, please! (You never use a dollar when setting a variable in Shell - only when using it in a readonly context)

The default environment variables that you're provided with effect the operation of your shell or commands called up within it in some way or other, and if you change the values they contain you'll effect the subsequent behaviour of the shell and its children.

$ echo $WINDOWMANAGER
/usr/X11R6/bin/kde
$
$ PS1='Hello: '
Hello: pwd
/home/trainee/korn
Hello: PS1='$ '
$

COMMENTS

In the Korn shell, any TOKEN that starts with a # character indicates that the rest of that command is to be treated as a comment.

$ echo "The # chacater starts a comment"
The # chacater starts a comment
$ echo If I type a # in a line
If I type a
$ # This is a comment
$

You are strongly encouraged to comment your scripts, using

- Blank lines to separate logical code blocks
- Major comments on line starting with # characters
- Specific notes about individual commands on the line ends

THE HISTORY MECHANISM

The Korn shell remembers the commands that you have run, and makes them available to you through the history mechanism. The actual command used is called fc, but it's aliased in several ways to other names.

$ history
29 PS1='Hello: '
30 pwd
31 PS1='$ '
32 echo The # character starts a comment
33 echo The # character oh - \
34 echo "The # chacater starts a comment"
35 echo If I type a # in a line
36 # This is a comment
37 alias
38 alias 'll=ls -l'
39 ll
40 ll /
41 FCEDIT=vi
42 export FCEDIT=vi
43
44 alias
$ r 35
echo If I type a # in a line
If I type a
$

Also note that $_ is an environent variable that means "last parameter, previous line".

You can also set up a command line editor so that you can interactively use your history list:

$ set -o vi
$

Then - ESC to enter command mode, KJHL for navigation, i, x, a and more.

Storing a shell program in a file

You won't always want to re-type your Korn shell instructions each time you want to run then, so you may store them in a file:

Here's the file "hello_korn"

# Demonstration of a file of Korn Shell commands

echo This example has been provided by Well House Consultants
echo -n "Copyright - " # Note quotes to add trailing space
date
ls !(h)*

and I can run it as follows:

$ ksh hello_korn
This example has been provided by Well House Consultants
Copyright - Sat Sep 22 10:38:05 BST 2007
hello_korn script_korn
$

But I have to KNOW that's a Korn script to run it - if I just want to type its name at the command line, I come across various issues:

$ hello_korn
ksh: hello_korn: not found
$ ./hello_korn
ksh: ./hello_korn: cannot execute - Permission denied
$

and even when I fix permissions:

$ ./hello_korn
This example has been provided by Well House Consultants
Copyright - Sat Sep 22 10:47:30 BST 2007
./hello_korn: line 8: syntax error near unexpected token `('
./hello_korn: line 8: `ls !(h)*'
$

Three things:

1. I should change permissions on the file to make it executable:
 chmod a+x hello_korn
or similar

2. I should specifiy at the top of the file that it is to be run under the Korn shell rather than any other, by adding a line
 #!/usr/bin/ksh

3. I might decide to change my path:
 export PATH=$PATH:.
but bear in mind that there may be security implications of adding any executable files you have in the current directory onto the list of executable syou may run.

It then works:

$ script_korn
This example has been provided by Well House Consultants
Copyright - Sat Sep 22 10:50:40 BST 2007
hello_korn script_korn
$

THE LIFE OF KORN SHELL

A new Korn shell doesn't just start up in isolation; rather, it starts up by reading in some initial settings from
 /etc/profile
 and $HOME/.profile
if it's a login shell, and then from a file named in $ENV. And if it's a shell which has been called in by another shell, it will inherit environment variables and functions which have been exported by that other shell.

Note the /etc/profile will usually contain directives to run additional shell startup scripts such as
 /etc/ksh.kshrc
 and $HOME/.kshrc

If a shell variable called HISTFILE is set, then the history will be reloaded from that file; if HISTFILE is not set, there's no re-loading of a previous session.

Commands available to the Korn Shell user / programmer

Like in Tcl, "everything is a command" in Ksh programming. In other words, as you analyse the syntax of the statements of the language you'll always find that, underlying everything else, you have a command name followed by a series of arguments. But there are several groups of commands:

SHELL BUILT IN COMMANDS

Commands in this group are included within the shell program itself, and may vary somewhat from other commands with the same name in othe Unix or Linux shell programs (you have been warned now, right?)

.
:
[
alias
bg
break
builtin
cd
command
continue
echo
eval
exec
exit
export
false
fc
fg
getopts
jobs
kill
let
print
pwd
read
readonly
return
set
shift
test
times
trap
true
typeset
ulimit
umask
unalias
unset
wait
whence

COMPOUND STATEMENTS / COMMANDS

Rather like the built in commands, these may vary in their Korn shell implementation to their implementation in other shells - although any that you use in the Bourne shell should wok directly here in ksh.

!
[[
case
do
done
elif
else
esac
fi
for
function
if
in
select
then
time
until
while
{
}

ALIASED COMMANDS

You can make up your own commands too, using the alias command

$ alias 'll=ls -l'
$ ll
total 168
-rw-r--r-- 1 trainee users 38 2007-09-22 07:21 body
-rw-r--r-- 1 trainee users 39 2007-09-22 07:18 demo
-rw-r--r-- 1 trainee users 2643 2007-09-22 07:11 first
-rw-r--r-- 1 trainee users 101 2007-09-22 07:21 head

Although useful, you should take care not to rely on too many of your own aliases if you regularly move from one Korn shell environment to another - you need to know the basics.

The following aliases are built in to the Korn shell

autoload='typeset -fu'
functions='typeset -f'
hash='alias -t'
history='fc -l'
integer='typeset -i'
local=typeset
login='exec login'
newgrp='exec newgrp'
nohup='nohup '
r='fc -e -'
stop='kill -STOP'
suspend='kill -STOP $$'
type='whence -v'

unalias will let you delete an alias.

SEPARATE PROGRAMS

The majority - the vaste majority - of commands you need will be separate programs, and you'll find them on your computer / file system in the various directories listed in $PATH.

$ echo $PATH
/usr/local/jboss/bin:/usr/local/ant/bin:/opt/SUNWappserver/bin:
/opt/SUNWappserver/jdk/bin:/home/trainee/bin:/usr/local/bin:/usr/bin:
/usr/X11R6/bin:/bin:/usr/games:/opt/gnome/bin:/opt/kde3/bin:
/usr/lib/mit/bin:/usr/lib/mit/sbin:.
$

Even commands as fundamental as ls and cp will be found as separate programs.

If you need to find out what comes from where, have a look at the whence command

$ whence ls
/bin/ls
$ whence ant
/usr/bin/ant
$ whence pwd
pwd
$ whence greet
greet
$ whence ll
'ls -l'
$

or if you prefer

$ whence -v pwd
pwd is a shell builtin
$ whence -v ll
ll is an alias for 'ls -l'
$ whence -v greet
greet is a function
$ whence -v whence
whence is a shell builtin
$ whence -v ln
ln is /bin/ln
$

FUNCTIONS

You can define your own command (script) within your script - nested scripts within the same shell if you like - as a function. A sort of heavy-weight alias, if you like.

$ vi funky
$ . ./funky
Hello World
$ greet
Hello World
$

Let's see the funky file:

#!/usr/bin/ksh

function greet {
        echo "Hello World"
        }

greet

Some common environment variables and settings

The set command allows lots of shell settings (switches) to be thrown.
-C noclobber
-n noexec (for checking)
-v verbose
-x xtrace - very useful for learning about how scripts work!
vi allows vi style command line editing

Environment:

CDPATH PATH EDITOR HISTFILE OLDPWD PPID PS1, 2 3 and 4 SECONDS


Korn Shell Programming

A FIRST PROGRAM AND A FIRST CONDITIONAL

Here's what you might consider to be your first script - it's four lines of code calling up mkdir, cp, ls, wc and sed programs and using a shell builtin echo to perform a backup, into a newly created directory named after the current date.

#!/usr/bin/ksh

# Korn Shell script (1) to back up files

mkdir `date +%F`
cp *.dat `date +%F`
echo -n "Backup copy(ies) made - file count = "
ls `date +%F` | wc -l | sed "s/[ \n]*//g"

How does it work?

$ ./dat_backup
Backup copy(ies) made - file count = 1
$ ./dat_backup
mkdir: cannot create directory `2007-09-22': File exists
Backup copy(ies) made - file count = 1
$

Very well the first time, but then it failed. And that's because mkdir tried to create a directory that already existed!

We can add to that code using a conditional - this first example uses a [ notation which the Korn shell inherits from the Bourne shell - a little ugly, but it works well enough:

#!/usr/bin/ksh

# Korn Shell script (2) to back up files
# Uses bourne shell compatible tests

if [ ! -e `date +%F` ]
then
        mkdir `date +%F`
        echo "Making new directory"
else
        echo "Overwriting directory"
fi
 
cp *.dat `date +%F`
echo -n "Backup copy(ies) made - file count = "
ls `date +%F` | wc -l | sed "s/[ \n]*//g"

And running:

$ ./dat_backup2
Overwriting directory
Backup copy(ies) made - file count = 1
$

Finally, a more flexible and potentially less ugly structure using [[ for the brackets is provided in the Korn shell. This is the one we'll carry on using later in this material.

$ r 145
rm -rf 2007-09-22
$ ./dat_backup3
Making new directory
Backup copy(ies) made - file count = 1
$ ./dat_backup3
Overwriting directory
Backup copy(ies) made - file count = 1
$

Here's the code I used:

#!/usr/bin/ksh

# Korn Shell script (3) to back up files
# Uses bourne shell compatible tests

if [[ ! -e `date +%F` ]]
then
        mkdir `date +%F`
        echo "Making new directory"
else
        echo "Overwriting directory"
fi
 
cp *.dat `date +%F`
echo -n "Backup copy(ies) made - file count = "
ls `date +%F` | wc -l | sed "s/[ \n]*//g"

ARRAYS AND LOOPS

In the Korn shell, all variables are actually arrays - yo do not declate them as such but simple set and get elements using a [ to ] notation. When referencing an element with the shell for reading, you have to help the shell with an extra { to } to delimit the variable name.

#!/usr/bin/ksh

# Setting up and referencing a Ksh array

county=Wiltshire
town[0]=Swindon
town[1]=Salisbury
town[2]=Chippenham
town[3]=Trowbridge
town[4]=Melksham
town[5]='Wootton Bassett'

print "We know about" ${#town[*]} towns in $county

print There is ${town[2]}
print There is ${town[4]}
print There is ${town[5]}

Note also the ${#town[*]} notation to count all members with any key.

$ ./pippa
We know about 6 towns in Wiltshire
There is Chippenham
There is Melksham
There is Wootton Bassett
$

The Korn shell supports while, until and for loops. Let's use examples to loop through our array of towns:

$ ./tracey
We know about 6 towns in Wilthshire
There is Swindon
There is Salisbury
There is Chippenham
There is Trowbridge
There is Melksham
There is Wootton Bassett
$

Here's the program for that:

#!/usr/bin/ksh

county=Wilthshire
town[0]=Swindon
town[1]=Salisbury
town[2]=Chippenham
town[3]=Trowbridge
town[4]=Melksham
town[5]='Wootton Bassett'

print "We know about" ${#town[*]} towns in $county

let a=0
while [[ $a -lt ${#town[*]} ]] ; do
        print There is ${town[$a]}
        let a+=1
done

It's down to which style you choose to use as to whether or not you put the do on the same line as the while, but if you elect to do so you must use that extra ; character.

The let command forces a piece of simple arithmentic (Korn shell maths is integer).

In an instance like this one, where the actual number associated with the town doesn't really matter to us, we may prefer to use a for loop to go through each of the values that's contained in the array, or a part of the array. Note that this for loop structure is quite different to the for loop structure in the C language if you're familiar with that.

$ ./sharon
We know about 6 towns in Wiltshire
There is Swindon
There is Salisbury
There is Chippenham
There is Trowbridge
There is Melksham
There is Wootton
There is Bassett
$

Notice the fact that my script turned "Wootton" and "Bassett" into two different towns!

#!/usr/bin/ksh

# for loop - Korn Shell

county=Wiltshire
town[0]=Swindon
town[1]=Salisbury
town[2]=Chippenham
town[3]=Trowbridge
town[4]=Melksham
town[5]='Wootton Bassett'

print "We know about" ${#town[*]} towns in $county

for place in ${town[*]}; do
        print There is $place
done

OTHER BRANCH CONTROLS

You have already seen if and else. There is also a case available, and you can test implicit conditions within valiables and calculations.

Also available are multiway branch case.

$ ./townline
Where are you wondering about
Orpington
Origin - House, Farm or group of huts
$ ./townline
Where are you wondering about
Chippenham
Saxon Origin
Origin - Village
$

Here's the source:

#!/usr/bin/ksh

# Selects a town ending

print "Where are you wondering about "
read placename

case $placename in
        *ham )
                print "Saxon Origin"
                result="Village";;
        *ton )
                result="House, Farm or group of huts";;
        *bridge )
                result="River Crossing";;
        *bury )
                result="Farm or Village";;
        *minster )
                print "Saxon Origin"
                result="Church";;
        * )
                result"Not in my table!";;
esac

print "Origin - $result"

OTHER LOOPS

You have already seen while and for.

There is also an until loop and a select statement which prompts for user entry and loops on error

$ ./selk
Where to you want to travel?
1) Swindon
2) Chippenham
3) Melksham
4) Trowbridge
5) Westbury
town? 7
invalid. Please try again
town? 3
You have entered Melksham
$

And the script that uses that select:

#!/usr/bin/ksh

PS3='town? '
print "Where to you want to travel?"
select place in Swindon Chippenham Melksham Trowbridge Westbury; do
    if [[ -n $place ]]; then
        print You have entered $place
        break
    else
        print 'invalid. Please try again'
    fi
done

AT THE END OF YOUR CONDITIONAL

You have already see fi and done and esac. Let's look at break, continue and retun.

break says "get me out of this loop .... NOW"

continue says "go back to the top of this loop for the next iteration"

and return says "leave this function .... NOW".

return takes a value as a parameter - the value to be returned

LOGICAL TESTS AND BALANCES

Exit statuses are the only things an if construct can test. But that doesn't mean you can check only whether or not commands ran properly. The shell provides a way of testing a variety of conditions with the [[ ]] construct.

Example of status check:

if cd ${dirname:?"missing directory name."}

Example of using the [ command (yes, really) to test a condition:

if [

And using the [[ construct.

if [[

STRING COMPARISONS

Use the operators = != < > -n and -z (careful - it's a single = sign!); -n for NOT null and -z for zero length.

Code sample:

#!/usr/bin/ksh

# String Test Operators - Ksh

print "Enter your name "
read something

if [[ $something = "Graham" ]] ; then
        echo "Hello Graham"; fi
if [[ $something != "Graham" ]] ; then
        echo "Hello Someone Else"; fi
if [[ $something < "Graham" ]] ; then
        echo "Hello Less Than Graham"; fi
if [[ $something > "Graham" ]] ; then
        echo "Hello Greater Than Graham"; fi
if [[ -n $something ]] ; then
        echo "Hello Someone"; fi
if [[ -z $something ]] ; then
        echo "Hello nobody"; fi

Testing ...

$ ./stroppy
Enter your name
Graham
Hello Graham
Hello Someone
$ ./stroppy
Enter your name
Harry
Hello Someone Else
Hello Greater Than Graham
Hello Someone
$ ./stroppy
Enter your name

Hello Someone Else
Hello Less Than Graham
Hello nobody
$

NUMERIC COMPARISONS

Remember - the Korn shell is an integer shell. Have a look at the bc command if you need to do floating point work.

Numeric comparisons are -eq, -ne, -lt, -le, -ge and -gt. Example:

#!/usr/bin/ksh

# Korn Shell - numeric (integer) testing

print -n "Please enter your age "
read yourage

if [[ $yourage -eq 21 ]] ; then
        print "Congratulations"; fi
if [[ $yourage -ne 21 ]] ; then
        print "Just another year then"; fi
if [[ $yourage -lt 21 ]] ; then
        print "A young one!"; fi
if [[ $yourage -ge 21 ]] ; then
        print "You're 21 on over"; fi
if [[ $yourage -le 21 ]] ; then
        print "You say you're 21 or less"; fi
if [[ $yourage -gt 21 ]] ; then
        print "A mature one"; fi

Testing code:

$ ./numtee
Please enter your age 33
Just another year then
You're 21 on over
A mature one
$ ./numtee
Please enter your age 13
Just another year then
A young one!
You say you're 21 or less
$ ./numtee
Please enter your age 21
Congratulations
You're 21 on over
You say you're 21 or less
$

FILE TESTS

-a file - file exists
-d file - file is a directory
-f file - file is a regular file
-r file - You have read permission on file
-s file - file exists and is not empty
-w file - You have write permission on file
-x file - You have execute permission on file
-O file - You own file
-G file - Your group ID is the same as that of file
file1 -nt file2 - file1 is newer than file2 (based on modification date)
file1 -ot file2 - file1 is older than file2

Let's try those out .. and also start using some command line arguments, which are available in ksh.

$* - all the command line parameters (see $@ if they may be null or have space) $1, $2, $3 etc - command line parameters one by one

#!/usr/bin/ksh

# Comparing one or two files

if [[ -z $1 ]] ; then
        print -u2 "Usage $0 filename [secondfilename]"
        exit
        fi

# If two files are given find which is newer

if [[ -n $2 ]] ; then
        if [[ $1 -nt $2 ]] ; then
                print "$1 is newer"
                use=$1
        else
                print "$2 is newer"
                use=$2
        fi
else
        use=$1
fi
print "About file $use ..."

if [[ ! -a $use ]]; then
    print "file $1 does not exist."
    return 1
fi
if [[ -d $use ]]; then
    print -n "$use is a directory that you may "
    if [[ ! -x $use ]]; then
        print -n "not "
    fi
    print "search."
elif [[ -f $use ]]; then
    print "$use is a regular file."
else
    print "$use is a special type of file."
fi

And some tests of that:

$ ./filestat sharon tracey
tracey is newer
About file tracey ...
tracey is a regular file.
$ ./filestat tracey sharon
tracey is newer
About file tracey ...
tracey is a regular file.
$ ./filestat .. .
. is newer
About file . ...
. is a directory that you may search.
$ ./filestat pippa
About file pippa ...
pippa is a regular file.
$ ./filestat pulla
About file pulla ...
file pulla does not exist.
$



See also Linux Basics Course

Please note that articles in this section of our web site were current and correct to the best of our ability when published, but by the nature of our business may go out of date quite quickly. The quoting of a price, contract term or any other information in this area of our website is NOT an offer to supply now on those terms - please check back via our main web site
Related Material

Web Application Deployment - Korn Shell - interactive and programming facilities
Web Application Deployment - Linux Utilities
Web Application Deployment - Linux -An Introduction For Users
resource index - Deployment
Solutions centre home page

You'll find shorter technical items at The Horse's Mouth and delegate's questions answered at the Opentalk forum.

At Well House Consultants, we provide training courses on subjects such as Ruby, Perl, Python, Linux, C, C++, Tcl/Tk, Tomcat, PHP and MySQL. We're asked (and answer) many questions, and answers to those which are of general interest are published in this area of our site.

You can Add a comment or ranking to this page


WELL HOUSE CONSULTANTS LTD.: Well House Manor • 48 Spa Road • Melksham, Wiltshire • United Kingdom • SN12 7NY
PH: 01144 1225 708225 • FAX: 01144 1225 793803 • EMAIL: info@wellho.net • WEB: http://www.wellho.net • SKYPE: wellho