![]() |
| |||||||
|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
What is the Shell? Just to recap on earlier tutorials: The shell in the programme that is running in your Terminal window: it is the shell that displays the prompt and waits for you to type a command. It then interprets what you've typed, goes away and does as you've asked, and returns for more. In Mac OS X the default shell, and therefore the one you are probably using, is 'tcsh' - the t-c-shell. A shell script is a sequence of commands written in a shell scripting language. Usually the commands are put in a file, and the file is read by the shell to execute the script. The shell reads the commands from the file and executes them, in much the same way as it reads commands typed at the command line. Of course, the same file can be executed many times. A shell script of any reasonable complexity will include both the familiar Unix commands (such as 'cd', 'ls', 'mv', and so on), and special commands that are part of the shell's own scripting language. These special commands control the flow of the script. For example, we can instruct the shell to rename a file if it exists, else display an error message to the user. Here the script has two actions, but only one of them is executed: which one depends upon some external condition. The Two Duties of a Shell A Unix shell has two duties: 1) To provide an interactive environment (the user interface). In this role we call it an interactive shell. This is where you type a command and the shell executes it. A good interactive environment will make your life at the command line easier. For example, the t-c-shell provides powerful command line editing and history (Part 2), current directory commands (Part 3), and re-direction and piping (Part 7). 2) To provide a shell scripting language. This is what we will cover in this and the next two tutorials. However, different shells have different scripting languages (see the side bar). The Dilemma Which shell scripting language do I teach? The standard language for writing Unix scripts is that of the Bourne shell. Most scripts are written for Bourne, the start-up scripts must use it, many Unix commands and daemons assume it, and most shells will run it - 'sh', 'bash', 'ksh', and 'zsh'. Mac Os X provides all these shells. The 'csh' and 'tcsh' run a different scripting language to all the others. Unfortunately, 'tcsh' is the default shell in Mac OS X. I say unfortunate because it is necessary to understand Bourne shell scripting whatever your day-to-day interactive shell is, so this is the one I will teach in these tutorials. I will not teach 'tcsh' scripting. However, I will give examples of 'tcsh' scripts along side the Bourne scripts. Fortunately, it does not matter which interactive shell you are running when you execute a script, because a new shell is launched to execute the script. With a little "!#" magic, we can ensure that the new shell will be the correct one for the script. |
Tell Me More...
|
|
Different Shells There are many shells available in Unix. The original shell was very basic, and was subsequently improved upon by the c-shell (called 'csh'), and the Bourne Shell (called 'sh'). The Bourne shell provided a good scripting environment, but lacked in the interactive environment. The c-shell was good for both, although most programmers preferred the Bourne shell for scripting. The scripting languages provided by 'sh' and 'csh' were incompatible. New shells were written that provided a much better interactive environment. - The t-c-shell ('tcsh') This improved on both the interactive and scripting language provided by 'csh'. - The Korn shell ('ksh'), Z shell ('zsh'), and the Bourne Again shell ('bash') These improved on the interactive environment of the Bourne shell, whilst remaining compatible with its scripting language. When writing shell scripts we therefore have the choice of two different scripting languages: that of csh/tcsh, and that of the Bourne shell and all the rest. |
Here is a very basic shell script. All it does is invoke a few commands just as you would do interactively on the command line. It is so simple that it does not use any elements of a shell scripting language, and can therefore be executed by any shell.
Create a file called, well anything you like, for example 'test.sh'. The file should contain the following commands, one per line.
cd / ls -al cd /Users ls -al cat ~/test.sh
Now execute the script with (assuming your current working directory contains the script):
./test.shDid that fail? You probably got a permission denied error. That's because you tried to execute the script, but the file does not have execute permission. Add execute permission by issuing the command:
chmod +x test.shand check permissions with:
ls -l test.shNow try again:
./test.shand you should see a couple of screens of output flash by before the prompt re-appears. Examine the output and you can see that it is exactly as if you had typed the same the five commands interactively. You can page the output from the script by piping it to less:
./test.sh | lessPress return to reveal more output, and 'q' to quite out of 'less'.
Creating a File
You must use a text editor to write scripts. Perhaps the easiest to use is 'pico'. Type:
pico test.shType in the text, hit control-o to write the file out, and control-x to exit pico. If you need to edit the file, use the cursor and delete keys much as you would with an Aqua-based editor. Trying to position the cursor using the mouse will not work.
|
You will be familiar with passing parameters (or arguments, I will use both terms) to Unix commands. For example, in the following: ls -l test.shwe give 'ls' two arguments - '-l' and 'test.sh' These arguments must be obtainable by 'ls' itself to be of any use. The same applies to shell scripts. Create a script file as below (I have used 'cat' to display the file on the Terminal): % cat params.sh #!/bin/sh Let's examine this script. Lines that begin with '#' are comments. They are ignored by the shell and you may follow the hash with any text you like. BUT - the first line of the script (and it must be the first): #!/bin/shis special. It says which shell is to be called to the execute script - in this case /bin/sh (the Bourne shell). This allows us to write Bourne shell scripts and ensure they are run by 'sh' even if our interactive shell is a different one, such as 'tcsh'. The next three lines display the first three parameters (arguments) passed to the script when it was executed. echo Parameter 1 = $1The echo command writes the text that follows to standard output. But note the $1 at the end. This is special. The Bourne shell interprets this as 'the value of parameter one' and replaces it with just that, before 'echo' is executed. Remember this: the shell interprets $1, not the echo command Now run the script and pass it two parameters, any text, such as 'param1' and 'the-second-parameter'. % ./params.sh param1 the-second-parameter Parameter 1 = param1 Parameter 2 = the-second-parameter Parameter 3 = Script name = ./params.sh The output from this script is the first two parameters, then a blank as $3 expands to nothing (we didn't pass a third parameter). The special parameter $0 contains the script name as invoked. The tcsh A script intended to be run by 'tcsh' instead of 'sh' must have the first line as: #!/bin/tcshThe above script will work in the 'tcsh' with no further changes. |
Tell Me More...
|
|
When a Script is Executed When we type ./params.shat the command line, your interactive shell takes a quick look at the start of the file, and sees the line: #!/bin/shIt then executes /bin/sh and passes 'params.sh' to it. It is the new shell that reads commands from 'params.sh' and executes them. When the script completes, the new shell terminates and control passes back to the original interactive shell. Why ./script-name? Why precede the script name with ./ ? The interactive shell searches for Unix commands (which includes shell scripts) using the search path defined by: % echo $PATHThis applies to scripts that you write yourself. If the current directory (assuming that is where your script is) is not in the search path, the shell will not be able to find the script. By using './script-name' to execute the script we are giving the full pathname of the script, and hence the shell does not have to refer to $PATH. No Money ($0) Execute 'params.sh' using the full pathname, eg: /Users/you/params.shand observe the new value of $0 as displayed in the output from the script. |
|
|
Like any programming language, shell scripts allow one to define variables. A variable is somewhere to place a value - a number, some text, today's date, etc. A variable can be set at one place in a script and the value recalled later. The value of a variable can be changed or added to as many times as required throughout the script. The script parameters $1, $2, etc are examples of special variables, set automatically before the script starts executing. A variable is set using the assignment operator '='. For example: % number=3Sets a variable called 'number' to '3'. The value can be recalled using the '$' operator: % echo $number3 To try this interactively, you must be running 'sh'. See the side bar. You can call your variables whatever you like. Start them with a letter and continue with letters, numbers, and underscores. The Bourne shell has a few reserved words that you must avoid using as variable names: - if then elif else fi case esac for while until do done -Write this simple script: % cat vars.sh #!/bin/shcombined="The number is $number, the filename is $filename, it is now $date" echo $number echo $filename echo $date echo echo $combined and execute it: % ./vars.sh letter docThe number is 3, the filename is letter.doc, it is now Wed May 7 11:25:28 BST 2003 Variable 'number' is simply set to 3. Variable 'filename' is set to the text that follows it. When executing such a statement, the shell firstly recalls the values of parameters and variables that are proceeded by the '$' operator, and then assigns the expanded value to the variable. In this case, the two parameters are expanded and 'filename' is set to the two parameters joined by a dot. Variable 'date' is set to the current time and date. How does this work? date=$(date)executes the Unix 'date' command in a sub-shell and captures its output. The output is then assigned to variable, also, but not necessarily, called 'date'. Any command or commands can be surrounded by brackets - try assigning the output from 'pwd', 'echo', and 'ls' to a variable. % listing=$(pwd;echo "contains:";ls)% echo $listing Variable 'combined' is assigned the text that follows the '=' operator, after $number, $filename, and $date have been expanded. The double quotes are necessary because the text to be assigned contains spaces. The tcsh To set a variable use: set number=3To get the output from a command use back-quotes: set listing=`(pwd;echo "contains:";ls)` |
Run 'sh' If you would like to try simple Bourne shell script commands interactively - ie on the command line - you must first run 'sh' (or 'bash', 'ksh', or 'zsh'). You are probably running the Mac OS X default shell 'tcsh'. To change to the Bourne shell type: % shand you will be talking to 'sh' instead of 'tcsh'. For example, try this: % sh sh-2.05a$ ls=$(ls) sh-2.05a$ echo $ls ... listing of current ... ... directory follows ... 'sh-2.05a$' is the default prompt displayed by 'sh'. Type: sh-2.05a$ exitto exit 'sh' and return to 'tcsh'. Instead of 'sh', you may use 'bash', 'ksh', or 'zsh' as they all understand the same scripting language. Vanishing Variables The variables set in a shell script persist while that script is executing. When the script finishes, variables vanish and cannot be recalled on the command line, or by other scripts. Special variables called 'Environment Variables' do persist, and we will discuss those in the next episode. Spaced Out It is VERY important to realise that spaces are significant. The statement: number = 3will not work. There must be no spaces either side of the '=' operator. Similarly: name=Adrian Mayowill not work, because of the space after Adrian. Use double quotes as in: name="Adrian Mayo"when a value contains spaces. TIP If in doubt, enclose the text to the right of the '=' operator with double quotes. |
Next Page
On page 2 I will introduce shell control flow with the IF statement, and give a few simple but useful shell scripts.
|
|
Part 8 - Shell Scripting 1 (page 1 of 2) |
|