the bourne shell cs465 - unix. bourne shell the bourne shell was the first widely used unix shell....

46
The Bourne Shell CS465 - UNIX

Upload: horatio-woods

Post on 02-Jan-2016

240 views

Category:

Documents


0 download

TRANSCRIPT

The Bourne Shell

CS465 - UNIX

Bourne Shell

• The Bourne shell was the first widely used UNIX shell. It is:

– the most common

– the easiest to learn

– used most often by beginning users

• This week we will cover the Bourne shell and its scripting features.

– Bourne scripts are portable to all versions of Unix.

Shells

• A shell can be used in one of two ways:

– A command interpreter, used interactively

– A programming language, to write shell scripts (your own custom programs)

Shell Scripts

• A shell script is just a file containing shell commands:– The first line of a shell script should be a comment of

the following form:#!/bin/sh (Bourne)

#!/bin/ksh (Korn)

• A line beginning with a hash character (#) is usually a comment. But #! is a special case:– Tells the shell which interpreter to run the lines of the

script under– If you leave it off, commands will be interpreted by

your interactive shell (in our case, ksh)

Shell Scripts

• Each line in a script file contains a command you could have typed at the command prompt

• A shell script must be readable and executable.

$ chmod +x scriptname

$ chmod 700 scriptname

• The shell script file has to be “in your path” to be executed.

– If the current directory (symbolized by . ) is not in your PATH, you must type ./scriptname to run it.

Simple Shell Script Example

• Here is a “hello world” shell script:

$ ls –lF h*

-rwxr-xr-x 1 smith 48 Feb 19 11:50 hello*

$ cat hello

#!/bin/sh

# comment lines start with # character

echo "Hello world"

$ helloHello world$

Variable Names

The shell provides for variable creation and usage.

There are basically two general categories of variables in UNIX:

– Shell Variables (Assigned by the Shell)

– User-Created Variables (Assigned by the user)

Displaying All Shell Variables

• Use the set command alone to display all variables:

$ setHOME=/home/small000LOGNAME=small000MAIL=/usr/mail/small000PATH=/bin:/usr/bin:/etc:PPID=24244PS1='$ 'PS2='> ':$

User-Created Variables • A user-created variable name can be any sequence of

letters, digits, and the underscore character, but the first character must be a letter.

• You do not have to “declare” variables.

• To create a new variable, simply assign a value to a variable name.

variableName=value

• Assigning values to a variables:number=25job=engineername="John Doe"

• There cannot be any spaces before or after the equal sign (=). (And there is no semi-colon!)

• Use double quotes to store strings containing with white space.

• NOTE: Internally, ALL values are stored as strings (even the numbers)

Assigning User-Created Variables

• To use a variable’s value, precede the variable name with a $

$ cat test1

#!/bin/sh

number=25

name="John Doe"

echo "$number $name"

echo '$number $name'

$

Using User-Created Variables

test125 John Doe$number $name$

Using Backquotes with Variables

• Remember that backquotes (graves) force command execution.

• Can use backquotes for variable assignment:

$ cat test2#!/bin/shuser=`whoami`numusers=`who | wc -l`echo "Hi $user! $numusers users logged on."$ test2

Hi small000! 6 users logged on. $

To eliminate a previously stored variable value: - assign a “NULL” value to the variable

OR

- use unset command.

Examples: name= unset number

De-assigning User-Created Variables

Displaying Dollar Signs• Use a backslash before the $ OR

• Use single quotes around the dollar sign

$ cat test4#!/bin/sh

cost=18.50echo "The total is: \$$cost "

echo 'Again, the total is $' $cost$ test4Enter amount: 18.50The total is $18.50

Again, the total is $18.50 $

Displaying Quotes• Enclose single quotes in double quotes• Enclose double quotes in single quotes• Or backslash the desired character

$ cat test5#!/bin/sh

echo "Doubles protect 'singles' " echo 'Singles protect "doubles" ' echo Single \' or double \"

$ test5Doubles protect 'singles'

Singles protect "doubles" Single ' or double "

$

Long Lines

• Within a script, a command can be "wrapped" to the next line by making the last character a backslash:

• Example:$ cat homedir

echo "My home directory is" \

$HOME

ls $HOME

$ homedir

My home directory is /home/smith

file1 file2 file3

$

Reading User Input• read is the shell's input command; it reads a line of

input and stores the result in one or more variables

• read’s arguments are the list of variables to store the input in:

– If you only list one variable, the entire line of input will be stored in it

– If you list more than one variable, the line will be split into words, using white space as the delimiter, and each variable will get one word

– If there are more words than variables, the last variable will store all the remaining words

Reading User Input

• Use the echo command to prompt the user

• Then use the read command to read a line of text into a variable.

Example: echo –n "Enter your full name: " read fullname -n option prompts user

for data on same line as message...

User Input within Scripts

test2Enter name:

Joe Smith

How many classes have you taken?

too many

Joe Smith has taken too many classes!

$

$ cat test2#!/bin/shecho "Enter name: "read nameecho "How many classes have you taken? "read numberecho "$name has taken $number classes "$

Missing User Inputs$ cat test3#!/bin/shecho "Enter name and number of classes: "read name numberecho "$name has taken $number classes!"$

$ test3Enter name and number of classes: 2525 has taken classes!$

test3Enter name and number of classes: JoeJoe has taken classes!$

Dividing Multiple User Inputs

test3Enter name and number of classes:

Joe Smith 25

Joe has taken Smith 25 classes!

$

$ cat test3#!/bin/shecho "Enter name and number of classes: "read name numberecho "$name has taken $number classes!"$

• Spaces indicate the end of input AND the last variable will read the input all the way to the end of the line.

Quoting Multiple User Inputs

test3Enter name and number of classes:

"Joe Smith" 25

"Joe has taken Smith" 25 classes!

$

$ cat test3#!/bin/shecho "Enter name and number of classes: "read name numberecho "$name has taken $number classes!"$

• Quoting the input does NOT override spaces as “end of variable input” indicators.

Variable Processing

• Special access

${var}• Same as $var, but useful when

variable name is followed by text

$ dept=CS

$ echo UNIX is ${dept}465

UNIX is CS465

$$ echo ${USER}\'s home dir is $HOME

brown345's home dir is /home/brown345

$

Positional Parameter Shell Variables

• Shell variables are used to store commands and related arguments

– You can use the set command to assign values to shell variables

– When you create shell scripts, the arguments after the script name are automatically stored into shell variables

Using the set command

• $1 to $9 are the first nine positional parameters

• To use the set command:

$ set Hello there class!

Results: $1 = Hello$2 = there$3 = class!

• The output of a command can be used to set the positional shell variables:

$ date

Fri May 16 11:04:03 MDT 2003

$

Positional Parameters

$ echo Today is $3 $2 $6Today is 16 May 2003

$

$* matches all variables $1 - $9

echo $* Fri May 16 11:04:03 MDT 2003 $

set `date` $ echo The time is $4 The time is 11:04:03 $

Positional Parameters within Scripts• $0 is name of command used to call script

• $1 to $9 are first nine positional parameters

• $* represents all positional parameters as one long string

• "$*" will put single pair of double quotes around the one long string

• $@ will put double quotes around each individual parameter

• $# contains number of parameters on the command line

$0 parameter

~/print1This script is called /usr/smith/print1$

$0 holds the name of the command the user typed to invoke the shell script:

$ cat print1#!/bin/shecho "This script is called $0"$ print1This script is called print1$ ./print1This script is called ./print1$

Using Positional Parameters• Example: A command to swap two files:$ cat swap#!/bin/shmv $1 tempfilemv $2 $1mv tempfile $2

rm tempfile$

swap notes1 notes2$ cat notes1contents of notes2$ cat notes2contents of notes1$

cat notes1contents of notes1$ cat notes2contents of notes2$

Using $* and $#$* lists all the command line args:

$ cat args1#!/bin/shecho The args are $*$ args1 a1 a2 a3 a4 a5 a6 a7 a8The args are a1 a2 a3 a4 a5 a6 a7 a8$

$# contains the number of args:

$ cat args2#!/bin/shecho The number of args is $#$ args2 a1 a2 a3 a4 a5 a6 a7 a8The number of args is 8$

Shifting Positional Parameters• Under the Bourne shell, you can only refer directly to

10 positional parameters: $0 to $9

– Note: Korn shell allows ${10} etc

• Can “pull” parameters beyond $9 into view with shift command:

– shift shifts parameters $1 - $9 left, allowing parameters beyond the first nine to be accessed

– Arguments "falling off" the left side are no longer available, so should be saved in other variables before the shift if they will be required later in the script

Shifting Positional Parameters

• After a shift• $2 becomes $1• $3 becomes $2• ....• ${10} becomes $9• Note: $0 does NOT change

• shift nn, where nn is a number, has the same effect as that number of shift commands

shift Example$ cat shiftargs#!/bin/shecho $*echo "Args: \$0 = $0, \$1 = $1, \$2 = $2"shiftecho "Args: \$0 = $0, \$1 = $1, \$2 = $2"shiftecho "Args: \$0 = $0, \$1 = $1, \$2 = $2"$ shiftargs arg1 arg2 arg3

arg1 arg2 arg3Args: $0 = shiftarg, $1 = arg1, $2 = arg2Args: $0 = shiftarg, $1 = arg2, $2 = arg3Args: $0 = shiftarg, $1 = arg3, $2 =

– The previous $1 becomes inaccessible each time

Locality of VariablesBy default, all shell variables you create are only available locally within your current shell (not from within a script or command subshells)

$ cat showdeptecho $dept$ dept=CS$ echo $deptCS$ showdept

$

All scripts are run in subshells, and dept was created in the parent shell, it is local to the parent shell and not available to the subshell.

Exporting Variables

• How can we make a variable available to script and command subshells?

Use the export command to export the variable to all subshells:

$ export varname 

Exported Variable Example

$ class=465

$ export class

$ cat showclass

echo CS $class

$ showclass

CS 465

$

class was created in the parent shell and exported. So it is availabe to use by any scripts running in subshells.

Exported Variable Values

• When a shell variable is exported, a COPY of the variable's value is made available to subshells.

• If the COPY's value is changed within the subshell, that change is NOT passed back to the parent shell

• The change is only accessible while you are still in the subshell.

Exported Variable Example

changeclassIn changeclass start: UnixIn changeclass end: Pascal$

$ class=Unix$ export class$ cat changeclassecho In $0 start: $classclass=Pascalecho In $0 end: $class$

echo $classUnix$

class has not changed in the parent shell.

Command Exit Values

• When a command completes it sets an integer called the return or exit status

• Conventionally:

– zero means no error

– non-zero means an error of some kind

• The shell control flow constructs will all take a zero status to mean true and a non-zero status to mean false

• $? is the exit status of the last command that was run

– Script can end with exit n where n is the exit status or condition code of the script

• Example:

$ cat exampleecho Helloexit 0$ exampleHello$ echo $?0$

Script Exit Status

Invoking a Shell Script

$ scriptname– Run a separate copy of the shell (a subshell) to

run the script (like we have been doing)

$ . scriptname– (dot space scriptname) Run the script within the

current invocation of the shell

$ shellname scriptname– Run a separate copy of the named shell to run the

script

$$ is the process ID (PID) of the current process (the shell script PID, or the shell PID if interactive).

$ ps PID TTY TIME CMD 892 pts/0 0:01 csh

$ echo $$892$

Special variable - $$

$ pidscript1154$ pidscript1156$

cat pidscript#!/bin/shecho $$$

$ cat newsh

ps

echo script PID is $$

$ csh newsh PID TTY TIME CMD 15083 pts/16 0:00 csh 15042 pts/16 0:00 ksh

script PID is 15083 $ echo $$15042$

Note: Overrides #! Setting in script

Running Under a Different Shell

Running without a Subshell(under the current shell)

$ echo $$

78392

$ cat testprog

echo $0 PID is $$

$ . testprog

testprog PID is 78392

$ echo $$

78392

$

wait command

• The wait command will cause a parent shell to wait until all children have completed.

• Can wait for a specific child if optional specific child PID is specified; otherwise waits for ALL children to complete.

• Format:

wait <child-PID>

Using wait

waitscriptwaitscript waiting. . . (parent)script1 running. . . (child)script1 done (child)child is done (parent)exiting waitscript (parent)$

$ cat script1echo $0 running. . .sleep 5echo $0 done$ cat waitscriptecho $0 waiting. . .script1 &waitecho child is doneecho exiting $0$