The commands in the shell are read one line at a time by the shell and executed in order. An extremely simple form of a shell script is shown below:
(zero.sh)
#!/bin/bash cd /home/mark pwd date |
If we were to take the contents of this file (shown above) and save it to a file named "zero.sh" it could be read by the shell, bash, to run the various commands it contains. The file name extension (.sh) does not have any bearing on the function of the script; it is used only to visually identify the file to the user.
|
||||
[mark@iguana unix] [mark@iguana unix] bash ./zero.sh /home/mark Thu Mar 4 20:56:54 EST 2004 [mark@iguana unix] |
bash
and that the path and name of the shell script
was the argument to that command. The shell bash
then read the contents of the file executing them in the order
that they were entered in the file. The script commands do not
appear on the terminal output, just their results. Commands that
do not print inforamtion to standard out are completely silent,
such as the cd
command in the example above.
There are generally a few more elements in a shell script and the script itself can be set as an executable file which will be explained further on.
(one.sh)
#!/bin/bash # comments follow the "#" character echo "Hello World" exit # another comment following a command on the same line. # done |
There are several items to take note of here:
#!/bin/bash
. The initial character pair
#!
tells the interactive shell that that this
script will be using it's own interpreter which is the
executable program that follows immediately, in this case
/bin/bash
. This line must be the
very first line and start at the first column - it may not
be indented. If this were a C shell
script the first line would be #!/bin/csh
. If
it were a Perl script the first line would be
#!/usr/bin/perl
.
#
character which unix shells recognise as
a comment and the line will be ignored. The
#
character does not have to start
the first column. Any text following the # character is
ignored by the shell.
echo
command.
exit
command tells the shell to stop
processing the script, quit and return to the shell or program
that started the script. Anything after the
exit
command will not be executed by the
shell. An exit
command is not necessary at
the end of a shell script since the shell will stop
processing the file once it reaches its end.
exit
command is a comment
string. This was added to show that comments do not have
to be entered on a line by themselves.
To run this shell script, it would need to be saved to a file.
It will be named "one.sh" in this example. It may be
run by using the file name as an argument to the shell
interpreter as was shown previously. That is not always
convenient as you'd have to find out what shell it was written
for before running it. Since we have defined the appropriate
shell at the beginning of the first line with the
#!/bin/bash
syntax,
all that needs to be done is to set the file permissions to
allow execution of the file.
|
||||
[mark@iguana unix] [mark@iguana unix] chmod u+x one.sh [mark@iguana unix] ./one.sh Hello World [mark@iguana unix] /home/mark/work/unix/one.sh Hello World [mark@iguana unix] |
It is important to remember that the shell which is running the shell script is not the same instance of the shell that is being used interactively by the user. The script runs in a separate, unique instance of the the command shell. Its environment variables, working directory and other parameters may be manipulated and changed independent of the interactive shell which is used to start the script.
env
?). These can be
manipulated with the commands export
and
unset
. In addition
to the environment variables there are also shell variables
which can be used in a similar manner but with a different
syntax. Use the =
sign to set and unset
to delete. The
values of either type of variable can be used by using the
variable name with a "$" character preceding it. See
the examlel below, "two.sh".
(two.sh)
#!/bin/bash # environment variables may be used in shell scripts echo $HOME # shell variables may be assigned values with the = sign testpath=/opt/kde ls -ld $testpath # shell variables may be removed with the unset command unset testpath echo $testpath exit # done |
When executed, this script produces the following output:
|
||||
> ./two.sh /home/mark drwxr-xr-x 9 root root 2048 Feb 23 10:44 /opt/kde > |
expr
command.
expr
has several other functions besides performing
mathematical calculations - see the man pages if interested.
Below are some simple examples of addition, subtraction,
multiplication and division:
#!/bin/csh # addition a = `expr 2 + 2` echo Addition equals $a # subtraction b = `expr $a - 1` echo Subtraction equals $b # multiplication (note that the * symbol needs to be escaped with the \ ) c = `expr $a \* $b` echo Multiplication equals $c # division d = `expr $c / 2` echo Division equals $d # more complex operations can be done as well. # parenthesis are reserved characters and need to be escaped as well expr \( -4 \* 3 \) + 2 exit # done |
expr
command
to a variable, the command must be placed between backtics
"`". This causes the expr
command to be
run/evaluated before assigned to the variable.
Below is the output from the script "three.sh":
|
||||
> expr 5 + 11 16 > ./three.csh Addition equals 4 Subtraction equlas 3 Multiplication equals 12 Division equals 6 -10 > |
File tests:
-r filename | Returns "true" if the filename exists and is readable |
-w filename | Returns "true" if the filename exists and is writable |
-x filename | Returns "true" if the filename exists and is executable |
-f filename | Returns "true" if the filename exists and is a regular file |
-d filename | Returns "true" if the filename exists and is a directory |
-h filename | Returns "true" if the filename exists and is a symbolic link |
-c filename | Returns "true" if the filename exists and is a character special file |
-b filename | Returns "true" if the filename exists and is a block special file |
-p filename | Returns "true" if the filename exists and is a named pipe |
-u filename | Returns "true" if the filename exists and its set-user-id bit is set |
-g filename | Returns "true" if the filename exists and its group-user-id bit is set |
-k filename | Returns "true" if the filename exists and its sticky bit is set |
-s filename | Returns "true" if the filename exists and has a size greater than 0 |
file1-nt file2 | Returns "true" if file1 is newer than file2 |
file1-ot file2 | Returns "true" if file1 is older than file2 |
file1-ef file2 | Returns "true" if file1 and file2 are the same file |
String Tests:
-z string | Returns "true" if the length of the string is 0 |
-n string | Returns "true" if the length of the string is > 0 |
string1 = string2 | Returns "true" if string1 and string2 are identical |
string1 != string2 | Returns "true" if string1 and string2 are not identical |
string | Returns "true" if the string is not NULL |
string1 < string2 | Returns "true" if string 1 is alphabetically before string2 |
string1 > string2 | Returns "true" if string 1 is alphabetically after string2 |
Integer Tests:
n1 -eq n2 | Returns "true" if the integers n1 and n2 are algebraically identical |
n1 -ne n2 | Returns "true" if the integers n1 and n2 are notalgebraically identical |
n1 -gt n2 | Returns "true" if the integer n1 is algebraically greater than the integer n2 |
n1 -ge n2 | Returns "true" if the integer n1 is algebraically greater than or equal to the integer n2 |
n1 -lt n2 | Returns "true" if the integer n1 is algebraically less than the integer n2 |
n1 -le n2 | Returns "true" if the integer n1 is algebraically less than or equal to the integer n2 |
bash
can control the execution of commands in a
shell script with the use of if, then
, and
else
. The if
statements use the
test operators listed in the previous section. Below are
several examples:
Example 1 (file test) (four.sh):
#!/bin/bash # check if the temp directory exists before changing directories. if [ -d $HOME/temp ] then cd $HOME/temp ls *.dat fi |
Example 2 (integer comparison) (five.sh):
#!/bin/bash # check if the variable $var1 is greater than 600 var1=200 if [ $var1 -gt 600 ] ;then echo $var1 is larger else echo $var2 is smaller fi # |
Example 3 (string comparison) (six.sh):
#!/bin/bash myname="george" # check if the variable $myname equals the shell environment variable $LOGNAME if [ $myname = $LOGNAME ] ; then echo $myname is $LOGNAME else echo $myname is not $LOGNAME fi # |
Multiple items can be tested with the case
statement. Each case
statement is tested against
the the value of the variable $VAL specified in the case
block. If none of the tests return "true" then
the default
item is executed.
Example 4 (case statement) (seven.sh):
#!/bin/bash VAL="No" echo val is $VAL case $VAL in yes) echo $VAL equals yes ;; No) echo $VAL is No date ;; X) echo value is $VAL date +%Y%m%d ;; *) echo Default option $VAL date +%j%Y ;; esac # |
for
loop nested within an
if
block.
(eight.sh)
#!/bin/bash VAL="no" if [ $VAL != "yes" ]; then for LTR ( A B C D 0 9 8 7 6 5 George ) do echo X $LTR ... done else echo failing because val is $VAL fi # |