Bourne shell acts on string variables of 3 types: user, shell, read-only
shell. Variables are assigned values with the
= operator and
referenced by value when prefixed by $. To assign values with
embedded blanks, quote or double quote the string. A variable can be declared
readonly using the builtin readonly, but then is cannot be reused as
read-write. A read-write variable can be removed by unset. Variables
are protected with braces as shown in the example below:
> cat cksh
a='This is a'
echo "${a}n example"
echo "$a test"
> cksh
This is an example
This is a test
| Shell variable evaluation rules (0),(1) | |
var= |
set variable to NULL |
$var |
value of var |
${var} |
value of var |
${var1-var2} |
value of var1 or var2 if var1 undef, or command `var2` |
${var=var1} |
set var = var1 if var undef |
${var?message} |
print message if var undef |
${var1+var2} |
value of var2 if var1 defined |
| (0) - No space allowed in brace expresssions. | |
| (1) - The operators may be prefixed by : to perform the same action, but only when | |
| the variable is set and not null | |
Scripts can handle arguments. Arguments are passed throught the positional
parameters $1..$9, while $0 is the name of the script (command)
itself. If you need more than 9 arguments, you can store in local variables the
first argument and use shift that shifts all arguments by 1 place.
Positional parameters are global and can be passed to nested scripts.
Parameters may be assigned as keywords with the following syntax:
par1=key1 par2=key2 key_commandNote that keywords are not counted by
$# and are recognized only if the
command is run from a Bourne shell:
$ sh $ cat cksh #!/bin/sh echo $a $b $ a=1 b=2 cksh 1 2 $ a=john b=mary cksh john maryIf cksh is run from another shell like tcsh, the following error message is typed:
> sh a=john b=mary cksh sh: a=john: cannot openTo use cksh from another shell, it must be called by the following script:
> cat sh0 #!/bin/sh sh & a=john b=mary ckshNote that sh must be called in background ( sh & statement)
Variables are made global to the sub-shells if declared in the export argument list. Exported variables are queried by export without arguments. Exported variable values are typed by env. Any single exported variable value is given by printenv var.
As in most shells, default field separators are <space> and <tab>. Other separators may be defined using IFS:
$ IFS=":"; export IFS # add : to field separatorsShell symbols are:
A script can be made executable in 5 different ways:$1..$9arguments$0process name$#no. of arguments at call$?exit status (0 = true = success, .not.0 = false = failure)$$PID of this shell$!PID of last background command$-option supplied at shell call$*full call args string$@call args with quotes
| script_name | run file script_name if +x permission set on file |
| sh script_name | fork new shell to run script_name ( -x) |
| . script_name | run script_name as part of current process ( -x) |
| exec script_name | run script_name in place of current process, |
| do not go back to original program | |
| `script_name` | replace script_name with script_name output |
A simple Bourne shell script example is the following:
> cat shodef #!/bin/sh #------------shodef: simple script to show date & dir--------------- # clear echo "current date & time: \c" date echo "user `whoami` at dir: \c" pwd echo #--------end script-----------
shodef clears the display ( clear), writes a comment suppressing
new line (\ c), shows the current time and date, writes a comment
including user name by executing ` whoami` (note the
backquote that forces execution of the embedded command) and prints current
directory on the same line, as shown below.
current date & time: Wed Jul 1 14:49:27 MET DST 1998 user jones at dir: /user/jones/devBackquotes can be nested in the form
\`:
$ jj=`echo date is` $ echo $jj date is $ jj=`echo date is: \`date\`` $ echo $jj date is: Tue Sep 8 15:41:01 MET DST 1998Another example of command substitution in cooperation with set:
> cat shodate
#!/bin/sh
#-----------shodate: example of set and `com`---------------
#
set `date` # insert date output in args
echo ""
echo "date command args are $# with values:"
#
echo ""
for args
do
echo $args # print all date items
done
#
echo ""
#------------end proc--------------------
The above example inserts in the arg list the item returned by date using set and the indirect command `date`, then the loop over arguments for args prints all arguments extracted from date.
> shodate date command args are 7 with values: Mon Jul 12 09:18:37 MET DST 1999 >
To inquire script items not typed as arguments on the command line Bourne shell
allows input from the keyboard with the read statement. Bourne
shells supports also the complete if structure with the
following syntax:
if ...
then ...
elif ... then
else
fi
A simple example of read and if is given below. Note also the
redirection to the empty device /dev/null of the grep operation. In
this way only grep status of is checked and grep output is
discarded.
#!/bin/sh #-----------inp: read input from tty # echo Proc $0: a demo of vt input echo echo "Please enter a name: \c" read name # #----check if $name logged------- # if who | grep -s $name > /dev/null then echo $name is logged else echo no such user $name fi #----------end script------------------ > inp Please enter a name: mary mary is logged > inp Please enter a name: john no such user john >Conditional execution is improved by the test statement. To check whether $file esists do:
#----check if $file exists------- echo "Please enter a file name: \c" read file if test ! -f $file then echo no such file: $file else ls -al $file fi #----------end script------------------ > exists Proc exists: A demo of the test command Please enter a file name: any no such file any > exists Please enter a file name: loop -rwxr-xr-x 1 james users 277 Jul 2 1998 loop >
The test command evaluates an expression constructed of functions and operators. If the value of expression is true, test returns an exit value of zero (0); otherwise, it returns FALSE, a nonzero exit value. The test command also returns a nonzero exit value if there are no arguments.
| test command syntax | |
| -r file | TRUE if file exists and has read permission |
| -w file | TRUE if file exists and has write permission |
| -x file | TRUE if file exists and has execute permission |
| -f file | TRUE if file exists and is a regular file |
| -d file | TRUE if file exists and is a directory |
| -e file | TRUE if file exists |
| -c file | TRUE if file exists and is a character-special file |
| -b file | TRUE if file exists and is a block-special file |
| -p file | TRUE if file exists and is a named pipe ( FIFO) |
| -h file | TRUE if file exists and is a soft link (same as -L [Digital]) |
| -L file | TRUE if file exists and is a soft link (same as -h) |
| -u file | TRUE if file exists and its set-user ID bit is set |
| -g file | TRUE if file exists and its set-group ID bit is set |
| -k file | TRUE if file exists and its sticky bit is set. [ Digital] |
| -s file | TRUE if file exists and has a size greater than zero ( 0) |
| -t descriptor | TRUE if the open file with file descriptor number descriptor |
| ( 1 by default) is associated with a terminal device | |
| -z string1 | TRUE if the length of string1 is zero ( 0) |
| -n string1 | TRUE if the length of string1 is nonzero |
| str1 = str2 | TRUE if str1 and str2 are identical |
| str1 != str2 | TRUE if str1 and str2 are not identical |
| string1 | TRUE if string1 is not the null string |
| num1 -eq num2 | TRUE if the integers num1 and num2 are algebraically equal. |
| Any of the comparisons -ne, -gt, -ge, -lt, and -le | |
| can be used in place of -eq | |
| The listed functions can be combined with the following operators: | |
| ! | Unary negation operator |
| -a | Binary AND operator |
| -o | Binary OR operator, -a operator has higher precedence |
| than -o operator | |
| EXIT VALUES | |
| 0 | The test command evaluated expression is TRUE |
| 1 | The test command evaluated expression is FALSE, |
| or there are no arguments | |
> 1 |
An error occurred |
Examples:
if test ! -s "$1"
then
echo $1 does not exist or is empty.
fi
The double quotes around $1 ensure that the test will work properly
even if the value of $1 is the empty string. If the double quotes are
omitted and $1 is the empty string, test displays the error
message test: parameter expected. Note that quotes and double quotes are
treated as in Korn shell.
if [ $# -lt 2 -o ! -s "$1" ]
then
exit
fi
If the shell procedure was given fewer than 2 positional parameters or the
file specified by $1 does not exist or is empty, then exit.
echo "\n \n Proc $0: A demo of the "elif" structure " if test $# = 0 then echo " supply file name !!!" elif test ! -f $1 then echo " no such file $1" else dir $1 fi
pattern1) command
;;
pattern2) command
;;
#!/bin/sh
#-----------excase: example of case statement
#
today=`date +%d/%m` #n.b. meaningful blanks
case $today in
16/07) echo "Thu 16 July"
;;
06/07) echo "Monday"
;;
10/07) echo "Meeting"
;;
*) echo "none"
esac
#
#----------end script------------------
In Bourne shell loops are implemented with the for, while, until
statements:
commands
# repeat commands if exit status == 0
commands
# repeat commands if exit status != 0
commands
#!/bin/sh
#-----------loop: example of while statement
#
while echo "Enter a command or end"
read cmd
do
case $cmd in
'end') break # end proc
;;
"") continue # ignore <ret>
;;
*) eval $cmd # do command
;;
esac
done
#
#----------end script------------------
A conditional exit is executed by exit n where n is an integer
giving the status.
Other less frequently used Bourne shell statements are:
(list)execute commands in a subshell{ list; }execute commnads in the current shellname () { list; }define a function referenced by name
Bourne shell can be run as a login shell set in /etc/passwd/ or as a subshell. Bourne shell is run by the sh command that is called in the form -sh when started as a login shell. In this case sh executes .profile and $HOME/.profile first. sh call flags are:
-c strrun commands from str-imake the shell interactive-rcreate a restricted shell-sread commands from stdin
| Bourne Shell Redirection Options | |
<file |
use file as stdin |
>file |
use file as stdout |
>>file |
append to file |
<<[-]EOF_str |
read till a line containing only EOF-str is met |
the dashed form <<- strips leading <tabs> |
|
< &n |
associate stdin with file descriptor n |
> &n |
associate stdout with file descriptor n |
< &- |
close stdin |
> &- |
close stdout |
| Bourne Shell set Synopsis | |
| Syntax: set [ + ][ -flag] [argument ...] | |
| To customize environment, use - to set flag and + to unset | |
| -a | mark for export all modified variables |
| -e | immediate exit on nonzero exit status |
| -f | disable file name substitution |
| -h | locate command called in function at function definition |
| (default is at function execution) | |
| -k | place all keyword parameters in the command environment |
| -n | read but do not execute commands |
| -t | exit after command execution |
| -u | treat unset variable as error |
| -v | trace shell input lines (debug mode) |
| -x | display command & arguments at execution (debug) |
| - - | do not change flags, useful for $1 starting with dash |
| Bourne Shell Built-in Commands | |
| : | null command |
| . file | execute command in current shell |
| break [n] | exit from loop |
| continue [n] | skip loop step |
| cd | change directory |
| echo | write arguments to stdout |
| eval | read arguments and execute commands |
| Ex. eval `tset -s vt100` sets term type | |
| exec | execute command in place of current shell |
| without creating a new process | |
| exit [n] | exit and optionally set exit status to n = 0:255 |
| hash [-] [name ...] | rehash command table |
| inlib | obsolete command, use loader instead |
| newgrp | change group (see also man page) |
| pwd | print current directory |
| read | assign var from stdin |
| readonly | mark var as readonly |
| return [n] | exit function with optional return status n |
| rmlib | obsolete command, use loader instead |
set [+| -flag] [arg] |
set flags 1 |
| shift [n] | shift left argument list |
| test | evaluate conditional expressions 2 |
| times | dispaly used time |
| trap | trap signals |
| type | indicate how the shell interprets the command |
| ulimit | display or adjust shell resources 3 |
| umask | set default file protection |
| unset | remove variable |
| wait [n] | wait child process n completion |
| (1) - see set synopsis | |
| (2) - see test syntax table | |
| (3) - see ulimit synopsis | |
| Bourne Shell ulimit Synopsis 0 | |
| Syntax: ulimit [-HS] -[a|c|d|f|h|m|n|d|t] [limit] | |
| default flag value: -f | |
| -a | set/display address space for the shell |
| -c | set/display core segment size for the shell |
| -d | set/display data segment size for the shell |
| -f | set/display file size for the shell |
| -h | set/display current hard resource |
| -H | set/display hard resource limit (superuser) |
| -m | set/display memory allocation for the shell |
| -n | set/display maximum open file descriptors for the shell |
| -s | set/display stack segment size for the shell |
| -S | set/display soft resource limit |
| -t | set/display CPU maximum time for the shell |
| (0) - for more information on resource setting see getrlimit | |