Special shell variables There are some variables which are set internally by the shell and which are available to the user: $1 - $9 these variables are the positional parameters. $0 the name of the command currently being executed. $argv[20] refers to the 20th command line argument $# the number of positional arguments given to this invocation of the shell. $? the exit status of the last command executed is given as a decimal string. When a command completes successfully, it returns the exit status of 0 (zero), otherwise it returns a non-zero exit status. $$ the process number of this shell - useful for including in filenames, to make them unique. $! the process id of the last command run in the background. $- the current options supplied to this invocation of the shell. $* a string containing all the arguments to the shell, starting at $1. $@ same as above, except when quoted : "$*" expanded into ONE long element : "$1 $2 $3" "$@" expanded into THREE elements : "$1" "$2" "$3" shift : $2 -> $1 ...) special characters The special chars of the Korn shell are : $ \ # ? [ ] * + & | ( ) ; ` " ' - A pair of simple quotes '...' turns off the significance of ALL enclosed chars - A pair of double quotes "..." : idem except for $ ` " \ - A '\' shuts off the special meaning of the char immediately to its right. Thus, \$ is equivalent to '$'. - In a script shell : # : all text that follow it up the newline is a comment \ : if it is the last char on a line, signals a continuation line qui suit est la continuation de celle-ci Evaluating shell variables The following set of rules govern the evaluation of all shell variables. $var signifies the value of var or nothing, if var is undefined. ${var} same as above except the braces enclose the name of the variable to be substituted. +-------------------+---------------------------+-------------------+ | Operation | if str is unset or null | else | +-------------------+---------------------------+-------------------+ | var=${str:-expr} | var= expr | var= ${string} | | var=${str:=expr} | str= expr ; var= expr | var= ${string} | | var=${str:+expr} | var becomes null | var= expr | | var=${str:?expr} | expr is printed on stderr | var= ${string} | +-------------------+---------------------------+-------------------+ The if statement The if statement uses the exit status of the given command if test then commands (if condition is true) else commands (if condition is false) fi if statements may be nested: if ... then ... else if ... ... fi fi Test on numbers : ((number1 == number2)) ((number1 != number2)) ((number1 number2)) ((number1 > number2)) ((number1 = number2)) ((number1 >= number2)) Warning : 5 different possible syntaxes (not absolutely identical) : if ((x == y)) if test $x -eq $y if let "$x == $y" if [ $x -eq $y ] if [[ $x -eq $y ]] Test on strings: (pattern may contain special chars) [[string = pattern]] [[string != pattern]] [[string1 string2]] [[string1 > string2]] [[ -z string]] true if length is zero [[ -n string]] true if length is not zero Warning : 3 different possible syntaxes : if [[ $str1 = $str2 ]] if [ "$str1" = "$str2" ] if test "$str1" = "$str2" Test on objects : files, directories, links ... examples : [[ -f $myfile ]] # is $myfile a regular file? [[ -x /usr/users/judyt ]] # is this file executable? +---------------+---------------------------------------------------+ | Test | Returns true if object... | +---------------+---------------------------------------------------+ | -a object | exist; any type of object | | -f object | is a regular file or a symbolic link | | -d object | is a directory | | -c object | is a character special file | | -b object | is a block special file | | -p object | is a named pipe | | -S object | is a socket | | -L object | is a symbolic (soft) link with another object | | -k object | object's "sticky bit" is set | | -s object | object isn't empty | | -r object | I may read this object | | -w object | I may write to (modify) this object | | -x object | object is an executable file | | | or a directory I can search | | -O object | I ownn this object | | -G object | the group to which I belong owns object | | -u object | object's set-user-id bit is set | | -g object | object's set-group-id bit is set | | obj1 -nt obj2 | obj1 is newer than obj2 | | obj1 -ot obj2 | obj1 is older than obj2 | | obj1 -ef obj2 | obj1 is another name for obj2 (equivalent) | +---------------+---------------------------------------------------+ The logical operators You can use the && operator to execute a command and, if it is successful, execute the next command in the list. For example: cmd1 && cmd2 cmd1 is executed and its exit status examined. Only if cmd1 succeeds is cmd2 executed. You can use the || operator to execute a command and, if it fails, execute the next command in the command list. cmd1 || cmd2 Of course, ll combinaisons of these 2 operators are possible. Example : cmd1 || cmd2 && cmd3 Math operators First, don't forget that you have to enclose the entire mathematical operation within a DOUBLE pair of parentheses. A single pair has a completely different meaning to the Korn-Shell. +-----------+-----------+-------------------------+ | operator | operation | example | +-----------+-----------+-------------------------+ | + | add. | ((y = 7 + 10)) | | - | sub. | ((y = 7 - 10)) | | * | mult. | ((y = 7 * 4)) | | / | div. | ((y = 37 / 5)) | | % | modulo | ((y = 37 + 5)) | | | shift | ((y = 2#1011 2)) | | >> | shift | ((y = 2#1011 >> 2)) | | & | AND | ((y = 2#1011 & 2#1100)) | | ^ | excl OR | ((y = 2#1011 ^ 2#1100)) | | | | OR | ((y = 2#1011 | 2#1100)) | +-----------+-----------+-------------------------+ Controlling execution goto my_label ...... my_label: ----- case value in pattern1) command1 ; ... ; commandN;; pattern2) command1 ; ... ; commandN;; ........ patternN) command1 ; ... ; commandN;; esac where : value value of a variable pattern any constant, pattern or group of pattern command name of any program, shell script or ksh statement example 1 : case $advice in [Yy][Ee][Ss]) print "A yes answer";; [Mm]*) print "M followed by anything";; +([0-9)) print "Any integer...";; "oui" | "bof") print "one or the other";; *) print "Default";; example 2 : Creating nice menus PS3="Enter your choice :" select menu_list in English francais do case $menu_list in English) print "Thank you";; francais) print "Merci";; *) print "???"; break;; esac done ----- while( logical expression) do .... done while : # infinite loop .... done while read line # read until an EOF (or ) do .... done fname # redirect input within this while loop until( logical expression) do .... done fout # redirect both input and output ----- for name in 1 2 3 4 # a list of elements do .... done for obj in * # list of every object in the current directory do .... done for obj in * */* # $PWD and the next level below it contain do .... done ----- break; # to leave a loop (while, until, for) continue; # to skip part of one loop iteration # nested loops are allowed in ksh ---- select ident in two # a list of identifiers do case $ident in one) ....... ;; two) ..... ;; *) print "none" ;; esac done Debug mode > ksh -x script_name or, in a 'shell script' : set -x # start debug mode set +x # stop debug mode Examples Example 1 : loops, cases ... #!/bin/ksh USAGE="usage : fmr [dir_name]" # how to invoke this script print " +------------------------+ | Start fmr shell script | +------------------------+ " function fonc { echo "Loop over params, with shift function" for i do print "parameter $1" # print is equivalent to echo shift done # Beware that $# in now = 0 !!! } echo "Loop over all ($#) parameters : $*" for i do echo "parameter $i" done #---------------------- if (( $# > 0 )) # Is the first arg. a directory name ? then dir_name=$1 else print -n "Directory name:" read dir_name fi print "You specified the following directory; $dir_name" if [[ ! -d $dir_name ]] then print "Sorry, but $dir_name isn't the name of a directory" else echo "-------- List of directory $dir_name -----------------" ls -l $dir_name echo "------------------------------------------------------" fi #---------------------- echo "switch on #params" case $# in 0) echo "command with no parameter";; 1) echo "there is only one parameter : $1";; 2) echo "there are two parameters";; [3,4]) echo "3 or 4 params";; *) echo "more than 4 params";; esac #---------------------- fonc echo "Parameters number (after function fonc) : $#" #------- To read and execute a command echo "==> Enter a name" while read com do case $com in tristram) echo "gerard";; guglielmi) echo "laurent";; dolbeau) echo "Jean";; poutot) echo "Daniel ou Claude ?";; lutz | frenkiel) echo "Pierre";; brunet) echo "You lost !!!"; exit ;; *) echo "Unknown guy !!! ( $com )"; break ;; esac echo "==> another name, please" done #------ The test function : echo "Enter a file name" read name if [ -r $name ] then echo "This file is readable" fi if [ -w $name ] then echo "This file is writable" fi if [ -x $name ] then echo "This file is executable" fi #------ echo "--------------- Menu select ----------" PS3="Enter your choice: " select menu_list in English francais quit do case $menu_list in English) print "Thank you";; francais) print "Merci.";; quit) break;; *) print " ????";; esac done print "So long!" Example 2 : switches #!/bin/ksh USAGE="usage: gopt.ksh [+-d] [ +-q]" # + and - switches while getopts :dq arguments # note the leading colon do case $arguments in d) compile=on;; # don't precede d with a minus sign +d) compile=off;; q) verbose=on;; +q) verbose=off;; \?) print "$OPTARG is not a valid option" print "$USAGE";; esac done print "compile=$compile - verbose= $verbose" Example 3 ############################################################### # This is a function named 'sqrt' function sqrt # square the input argument { ((s = $1 * $1 )) } # In fact, all KornShell variables are, by default, global # (execpt when defined with typeset, integer or readonly) # So, you don't have to use 'return $s' ############################################################### # The shell script begins execution at the next line print -n "Enter an integer : " read an_integer sqrt $an_integer print "The square of $an_integer is $s" Example 4 #!/bin/ksh ############ Using exec to do I/O on multiple files ############ USAGE="usage : ex4.ksh file1 file2" if (($# != 2)) # this script needs 2 arguments then print "$USAGE" exit 1 fi ############ Both arguments must be readable regular files if [[ (-f $1) && (-f $2) && (-r $1) && (-r $2) ]] then # use exec to open 4 files exec 3 <$1 # open $1 for input exec 4 <$2 # open $2 for input exec 5> match # open file "match" for output exec 6> nomatch # open file "nomatch" for output else # if user enters bad arguments print "$ USAGE" exit 2 fi while read -u3 lineA # read a line on descriptor 3 do read -u4 lineB # read a line on descriptor 4 if [ "$lineA" = "$lineB" ] then # send matching line to one file print -u5 "$lineA" else # send nonmatching lines to another print -u6 "$lineA; $lineB" fi done print "Done, today : $(date)" # $(date) : output of 'date' command date_var=$(date) # or put it in a variable print " I said $date_var" # and print it... Example 5 ############ String manipulation examples ################## read str1?"Enter a string: " print "\nYou said : $str1" typeset -u str1 # Convert to uppercase print "UPPERCASE: $str1" typeset -l str1 # Convert to lowercase print "lowercase: $str1" typeset +l str1 # turn off lowercase attribute read str2?"Enter another one: " str="$str1 and $str2" #concatenate 2 strings print "String concatenation : $str" # use '#' to delete from left # '##' to delete all # '%' to delete all # '%%' to delete from right print "\nRemove the first 2 chars -- ${str#??}" print "Remove up to (including) the first 'e' -- ${str#*e}" print "Remove the first 2 words -- ${str#* * }" print "\nRemove the last 2 chars -- ${str%??}" print "Remove from last 'e' -- ${str%e*}" print "Remove the last 2 tokens -- ${str% * *}" print "length of the string= ${#str}" ######################## # Parsing strings into words : typeset -l line # line will be stored in lowercase read finp?"Pathname of the file to analyze: " read fout?"Pathname of the file to store words: " # Set IFS equal to newline, space, tab and common punctuation marks IFS=" ,. ;!?" while read line # read one line of text do # then Parse it : if [[ "$line" != "" ]] # ignore blank lines then set $line # parse the line into words print "$*" # print each word on a separate line fi done < $finp > $fout # define the input & output paths sort $fout | uniq | wc -l # UNIX utilities