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
Web Application Deployment - Korn Shell - interactive and programming facilities [1660] Korn shell - some nuggets - (2008-05-30)
[1659] String, Integer, Array, Associative Array - ksh variables - (2008-05-30)
[1658] Some useful variables and settings in the Korn Shell - (2008-05-30)
[1367] korn tips - some useful korn shell techniques - (2007-09-25)
[1365] Korn Shell scripts on the web - (2007-09-25)
[1364] Korn shell course - resources - (2007-09-24)
[1361] Korn shell course - (2007-09-22)
Web Application Deployment - Linux Utilities [4682] One line scripts - Awk, Perl and Ruby - (2016-05-20)
[4586] Extending your bash shell with aliases, functions and extra commands - (2015-11-28)
[3902] Shell - Grep - Sed - Awk - Perl - Python - which to use when? - (2012-10-22)
[3764] Shell, Awk, Perl of Python? - (2012-06-14)
[3446] Awk v Perl - (2011-09-18)
[2638] Finding what has changed - Linux / Unix - (2010-02-17)
[2484] Finding text and what surrounds it - contextual grep - (2009-10-30)
[2320] Helping new arrivals find out about source code examples - (2009-08-03)
[2145] Using the internet to remotely check for power failure at home (PHP) - (2009-04-29)
[1690] Conversion of c/r line ends to l/f line ends - (2008-06-28)
[1366] awk - a powerful data extraction and manipulation tool - (2007-09-25)
[1361] Korn shell course - (2007-09-22)
[71] Comparators in Linux and Unix - (2004-10-03)
[63] Almost like old times - (2004-09-26)
Web Application Deployment - Linux -An Introduction For Users [3819] Packing a tar, jar or war file - best practise - (2012-07-26)
[3791] The Kernel, Shells and Daemons. Greek Gods in computing - (2012-07-01)
[3256] Displaying a directory or file system tree - Linux - (2011-04-22)
[3179] Oops - I typed ci not vi, and have lost my file ... - (2011-02-21)
[2831] Recording (a macro) in vi - (2010-06-27)
[2636] Linux - useful tips including history and file name completion - (2010-02-15)
[2494] Making Linux Politically correct - (2009-11-06)
[2479] Accidentally typed ci rather than vi? - (2009-10-27)
[2300] What does x on a linux directory mean? - (2009-07-21)
[2299] How much space does my directory take - Linux - (2009-07-20)
[2203] Always use su with minus. And where do programs come from? - (2009-05-27)
[2201] Running straight from the jar, but not from a tar - (2009-05-26)
[1904] Ruby, Perl, Linux, MySQL - some training notes - (2008-11-23)
[1902] sstrwxrwxrwx - Unix and Linux file permissions - (2008-11-23)
[1897] Keeping on an even keel - (2008-11-21)
[1893] Some Linux and Unix tips - (2008-11-18)
[1803] FTP passive mode - a sometimes cure for upload hangs - (2008-09-20)
[1764] Yank and Push - copy and move in vi - (2008-08-21)
[1651] ls command - favourite options - (2008-05-23)
[1527] Selecting file names in a shell - one word or another - (2008-02-02)
[1438] Copy and paste / cut and paste and other vi techniques - (2007-11-20)
[1408] Wireless hotel tips - FTP and Skype connections failing - (2007-10-26)
[1366] awk - a powerful data extraction and manipulation tool - (2007-09-25)
[1288] Linux run states, shell special commands, and directory structures - (2007-08-03)
[1287] Work and play at Well House Manor - Football and Shell Shortcuts - (2007-08-02)
[1259] Where am I and how did I get here? - (2007-07-05)
[1068] ls -l report, Linux / Unix - types and permssions - (2007-02-06)
[1013] Copy multiple files - confusing error message from cp - (2006-12-30)
[1012] Moving files between Windows / DOS and Linux / Unix - (2006-12-30)
[984] Cardinal numbers and magic numbers - (2006-12-14)
[749] Cottage industry or production line data handling methods - (2006-06-07)
[711] THE home directory or MY home directory - (2006-05-06)
[710] Linux training Glasgow, Python programming course Dundee - (2006-05-05)
[703] Copying files and preserving ownership - (2006-04-28)
[679] More or less on the edge of the page - (2006-04-11)
[659] Web Application Components - (2006-03-28)
[593] Finding where the disc space has gone - (2006-02-06)
[431] File permissions of Linux and Unix systems - (2005-08-31)
[430] Linux commands - some basics - (2005-08-31)
[249] An easy way out - (2005-03-17)
[152] Aladdin, or careful what you wish. - (2004-12-15)
[74] pushd and popd - (2004-10-05)
[73] vi - full circle - (2004-10-04)
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, Lua, 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.