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:
#!/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]
bashand that the path and name of the shell script was the argument to that command. The shell
bashthen 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
cdcommand 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.
#!/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
#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.
exitcommand tells the shell to stop processing the script, quit and return to the shell or program that started the script. Anything after the
exitcommand will not be executed by the shell. An
exitcommand is not necessary at the end of a shell script since the shell will stop processing the file once it reaches its end.
exitcommand 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
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
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
unsetto 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".
#!/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 >
exprhas 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
exprcommand to a variable, the command must be placed between backtics "`". This causes the
exprcommand 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 >
|-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|
|-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|
|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|
bashcan control the execution of commands in a shell script with the use of
if, then, and
ifstatements 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 is tested against
the the value of the variable $VAL specified in the
block. If none of the tests return "true" then
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 #
forloop nested within an
#!/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 #