Free Web space and hosting from 00server.com
Search the Web


Hi charlie

merry christmas.





Love halle.

www.halleelfyours elf.com/

ok. now that halle berry, angelina jolie, brad pitt, matt damon, george clooney, jessica alba, rosario dawson, rihanna, vanessa hudgens, ellen page and hayden panettiere have gotten your attention. today's lesson is on advanced unix scripting.

i am charles gilberg. and i was at michigan state when the inception of fractal geometry was born from the prism effect. i was in indiana when einstein's incomplete theory of relativity was completed. and you will find that stephen hawkings theory of the black hole has been completed at this web address: http://nerdyguyanon.livejournal.com/

this book provides the user with a comprehensive understanding of advanced scripting. advanced scripting teaches the user how to use some of the many thousands of program commands that are available in each standard of the unix manual page's, to enable the user to put together the language of unix shell scripts in comprehensive syntax form to create working program scripts and program files.

1. three main uses for unix shell scripts?

the three main uses for unix shell scripts are automation of common tasks, unix system administration via the use of shell scripts, and the use of interactive and data driven cgi programing, often written in bourne shell for processing data and constructing interactive web pages.

2. what is the unix shell?

a shell is a program that is used to start other programs.

the dos shell is command.com.
the shell for windows 3.1 and windows nt 3.x is program manager.
and the shell for windows 95/98/me/nt4/2000/xp is windows explorer.

commands are written with a particular syntax on the command line.

the requirement of a particular syntax, and the facility to read those commands from a text file may be thought of as a programing language, and programming files may be thought of as files whose data are scripts. thus the shell is a user interface between the user and programs for the purpose of starting programs, and the shell is a programing language. the dos shell is a programing language because it interprets batch files similarly to unix interpreters.

3-4. which shell?

95% of the world's shell scripts are created for use with the bourne shell. there are a number of bourne shell derivatives, the korn shell, ksh by david korn. the bash shell, bourne again shell, and zsh shell, are all purported to be bourne compatible shell.

the c-shell csh and tcsh family of shells are closely related to the c programming language, and are almost completely incompatible with the bourne shell.

5. what is a shell script?

some files on unix are deemed executable files because the shell script in these files execute programs. and the data input and output to these files are used by the executable files.

some of these programs are compiled from machine source code such as c, cobol, and pascal known as binary executable files. the compilation process converts the binary executable files into a human readable language known as scripts.

scripts are fully human readable text files. there are two types of programs, text scripts and binary executables. there are many types of interpreters to create and edit scripts such as awk, sed, perl, but bourne shell is the most popular interpreter in unix. thus, the shell architecture in unix is executable program, scripts, and shell scripts.

example of a script for rotating a log file by removing the 6th log each time a new log is entered:

#!/bin/sh # the script interpreter /bin/sh is specified by #!.
#
# rotate program log files
#
cd /home/charles/course/logfiles

# data input and output to these files are used by the executable files.

rm program.log.6
mv program.log.5 program.log.6
mv program.log.4 program.log.5
mv program.log.3 program.log.4
mv program.log.2 program.log.3
mv program.log.1 program.log.2
mv program.log program.log.1
# each time a new file is created the rotation of files is caused by the removal and # replacement of the rm program.log.6 command.

1. a basic script?

you create a script in a text file and use the chmod +x filename program command to make the file executable.

# here we use a vi editor to create some code, save it to a filename and make that file # executable.

example: vi filename. then in insert mode, add the program commands:

pwd # when run the pwd program tells the user the current directory.

ls -C # ls -C lists files in a column and date displays the current date and time. date

:w # colon w to save the file.
:q # colon q to quit the editing program.

at the prompt type: chmod +x filename to make the file executable.

to run the file as a program from your current directory type dot forward slash ./filename to find for the filename in the current directory and execute it. if the directory that contains your script is in your current path you may simply type its filename to get it to run. the . dot is the current directory / forward slash is the path you are searching and filename is the file that contains the script you are trying to execute.

echo $PATH to see if the directory is in the current path and, if your path begins or ends with a ":" then your path includes your current directory. any unix command from the unix man pages that can be typed on the command line may be added to a script that you are trying to run, and that script will run.

2. echo command?

the echo program command is a built in shell command, which means there is not an executable file called echo. instead the echo command is processed internally by the shells architecture. and any command parameter can be echoed out to the standard output. echo is like a -print statement or in c programming a printf statement. and if no parameter is given to echo a blank line is output.

echo is primarily used to display messages to the user:

echo the current directory is: # this echo tells the user the pwd present working directory,

pwd # pwd program tells the user the current directory.
ls -C # and lists the files ls -C in a column.
echo the current date and time is: # this echo tells the current date and time.
date

to make the output more user friendly, we will use echo to create a blank line.

echo the current directory is: pwd # pwd tells the user the present working directory.
echo # this echo is not written to request any parameters and gives a blank line.
echo the contents of the current directory is:
# this echo requests a string of text which is preceded by a command.
ls -C # ls -C lists the files in a column.
echo # this echo is not written to request any parameters and gives a blank line.
echo the current date and time is:
# this echo requests a string of text which is preceded by a command.
date # the date program command tells the current date and time.

3. read command?

the read program command is a built in shell command for reading and storing data in a shell variable. the read standard input information usually comes from the keyboard.

example: read name creates a variable called name, and the value of input that was put into the variable name can be examined by typing echo $name. the $ dollar sign is used to extract or request the value from the variable name.

example of combing a variable with normal text:
echo the current directory is:
pwd # pwd program tells the user the current directory.
echo # this echo is not written to request any parameters and gives a blank line.
echo the contents of the current directory is:
ls -C # ls -C lists the files in a column.
echo # this echo is not written to request any parameters and gives a blank line.
echo the current date and time is:
# this echo requests a string of text which is preceded by a command.
date # the date program command tells the current date and time.
echo # this echo is not written to request any parameters and gives a blank line.
echo please enter your name. # this echo instructs the user to enter their name.
read name
# read, reads the specific data information pieces input to name from the name that is
# typed in on the command line.
echo hello $name, how are you? # the "$name" variable is combined with normal text.

read can break the variable line of output into several variables. the shell breaks up the read variable line into chunks. each chunk is derived from data that you type in, and is separated by spaces and or tabs.

echo the current directory is:
pwd # pwd program tells the user the current directory.
echo # this echo is not written to request any parameters and gives a blank line.
echo the contents of the current directory is:
ls -C # ls -C lists the files in a column.
echo # this echo is not written to request any parameters and gives a blank line.
echo the current date and time is:
date # the date program command tells the current date and time.
echo # this echo is not written to request any parameters and gives a blank line.
echo please enter your name:
read name
# read, reads the specific data information pieces input to name from the name that is
# typed in on the command line.
echo hello $name, how are you? # the "$name" variable is combined with normal text.
echo # this echo is not written to request any parameters and gives a blank line.
echo what is your current address?
read number street type
# read, reads the specific data information pieces input to name from the name that is
# typed in on the command line.
# the read variable line of output that is broken into several variables the read variables are
# broken into number street, and type.

the echo -n option places the _curser that will be waiting for a response on the same line assigned to the output message rather than beneath it. to add extra spaces anywhere in the echo message the whole message has to be surrounded in " double quotes.

echo -n please enter your name._

echo -n "please enter your name. "_ # echo message surrounded in " double quotes
# to allow for space.

not all versions of echo support the version of -n option, and will not echo the -n option along with the message output onto the screen. by placing \c at the end of the message line, and the \c inside the double quotes, the spaces and _curser will be preserved on the same line as the message.

echo "please enter your name. \c"_ # note the space before name \c.


4. shell basics revisited?


the standard output of any program including scripts can be redirected using the > output command. if a file does not already exists it is created, if the file already exists it is over written.

to create the file using the > output command you have to have permission over the directory. to write over the file using the > output command you have to have permission over the file you are creating or giving the data to.

example: who > wholist # who gives output as input to the wholist file.

additional standard output of any program can be >> appended to the end of any file as additional data.

example: cat /etc/passwd >> userlist
# cat appends or adds /etc/passwd to the end of the userlist file.

the standard output of any program can be piped to the input of any other program that takes input by using the | pipe command.

example:
who | wc -l # who examines a list of who is logged on the server and pipes | that
# output to wc word count the lines -l of persons logged on.

you can also combine programs and send the output to a file.

example:
who | wc -l > usercount file
# the who data is piped | as output to wc -l which takes the input, processes it and outputs
# it to the usercount file.

standard input can be read from any file by using the input < command.

example of standard input being read from a file:
cat askname # cat reads the data from the askname file.

echo "please enter your name: \c"
# the three lines of script that allow data to be input to the askname file are stored in the
# askname file.
read name
# read, reads the specific data information pieces input to name from the name that is
# typed in on the command line.
echo hello $name.

cat myname # the myname file contains the name data that is input < into the askname file.
charles gilberg

askname < myname # the myname file inputs data into the askname file. please enter your name: hello charles gilberg.
# askname command receives the name value data that was input in the myname file.

standard error output is a separate output stream than that of standard output, and may be redirected to a file using 2>.

example: find . -name charles.txt > resultsfile and to 2> errorsfile
# find, finds in the current directory the name charles .txt and gives its output to
# the resultsfile and sends the errors to 2> the error file.

standard output and standard error can be redirected to the same file with 2>&1. the 2>&1 sends 2 error output to the same file as the standard output 1 file.

example:
backup > resultsfile 2>&1
# backup gives all output including the errors to the results file 2>&1 to the same file as
# the standard output 1 file.

any unneeded output can be redirected to the special /dev/null file where the unneeded information will simply disappear.

example: find . -name charles.doc 2> /dev/null
# find within the current directory charles.doc and all other information is discarded as
# errors and sent 2> to /dev/null.

commands may be run asynchronously in the background by placing an & ampersand at the end of the command on the command line. and that means, you get your prompt back immediately while the program runs in the background.

example:
nohup backup &
# the nohup program runs the backup uninterrupted in the background &.

5. special characters?

characters that are special to the shell:
& ampersand allows you to run programs asynchronously in the back ground.

* asterisk is used as a wildcard in filename expansion to match any character in a filename.
example:
*.txt # any characters dot txt.
mark.* # mark dot any characters.
a*b # any characters between a and b.
and *.* # any characters with a dot in it.

? question mark matches any single character.
example:
c?t # any single character between c and t.
fred.???? # fred dot four single characters.
and ????x? # four single characters with an x before any other single character.

[ ] square brackets match only any single character at a time that is within the square brackets.
example:
c[aou]t [a-zA-Z]*.txt [!d]*
# match an a, o, or u between c and t, and a through z or either capital A through Z and
# any characters dot txt, and not d but any other character.

the ! exclamation character means do not match the character that the exclamation mark is prefixed to.

< less than redirects standard input to receive input from < a file(s), program(s) or directory(s).
> greater than redirects standard output to give output to > a file(s), program(s) or directory(s).
| pipe, pipes output from one command into the input of another command. in a pipe one program must create output that must be used as input to the other program.

example:
who lists who is currently logged in on the sever and pipes | that information to wc word count, which counts -l the lines.

special characters should be avoided when naming filenames, and / forward slash should never be used when naming a file.

if it is necessary to pass a special character as a parameter to another program you may prefix the special character with a back slash. a delimiter separates the value of the character that it precedes. example: \$

you can surround the special character with a pair of double " " quotes. example: "#"

and you can surround the special character with ' ' single quotes, which work well for all characters except ' the single quote.
example: '$'.

6. comments?

the hash # character is used to create a comment. a comment is a human readable explanatory text that is added to a script as a note to make what the code does more understandable.

a # comment causes the text on the line that follows it to be completely ignored by the shell.

example:
# count the number of users logged onto the system.
who | wc -l # counts only the lines of users who are currently logged in on to the server.

comments are an important part of software development. the use of comments cut down drastically on maintenance, time and cost.

7. exercise?

#
# create a fully commented script that prompts the user for their
# name, address and phone number. all details should be stored in a file.
#
# also display a message that tells which file the details are stored in.
#
#

#
# first, prompt for the users name.
#
echo "please enter your name: \c"
read name
echo name: $name > details.file
# name data is displayed and > output name data is sent to the details.file

#
# next, prompt for the users address.
#
echo "please enter your address: \c"
read address
echo address: $address >> details.file
# address data is displayed and >> output address data is added to the details.file

#
# next, prompt for the users phone number.
#
echo "please enter your phone number: \c"
read phone
echo phone: $phone >> details.file
# address data is displayed and >> output phone data is added to the details.file

#
# finally, display the message that tells the user which file the details are stored in.
#
echo thank you. the details have been stored in \"details.file\".
# the echo message displays in quotes which file the data is stored in.

#
# create an automated, fully commented script that gives the possible number of users
# on the system, the number of users currently logged in on the system, and the total
# number of processes running.
#

#
# first, the number of possible users on the system.
# these can be found in the "/etc/passwd" file.
#
echo "the number of possible users on the system are: \c
# \c is used to line up the output in columns.

cat /ect/passwd | wc -l
# cat /etc/passwd pipes | output to wc word count -l the pass word lines of the pass
# word file.

#
# next, use the who program command to display all users currently logged in.
#
echo "the number of users currently logged onto the system: \c"
who | wc -l
# who pipes | output to wc word count -l the lines of users logged in on the server.

#
# finally, use the ps -e program command to display the total number
# of processes running.
#
echo "the total number of processes running: \c"
ps -e | wc -l
# ps -e process every, pipes | output to wc word count -l the lines of every process that
# is currently running on the server.

1. running a shell script?

there are four ways to run a script. when running a script from a file that's been made executable, a copy of the shell is made that executes the script from the file. if any variables are set, the value of those variables are lost as soon as the shell script stops running.

assignment example: greetings=hello # greetings is assigned the value hello. echo $greetings # the hello value is extracted using the $ variable greetings. hello

2. without making a file executable, you can type sh filename, and a second shell is loaded into memory and runs the contents of the file filename. and this works whether or not the file is made executable.

3. when you type ./filename, to run the script, no second shell is loaded into memory. therefore the values of that script persist after the shell script stops running.

4. if you type in the subprocess control exec filename, the current shell immediately terminates, spawning an execute shell script. and as soon as the shell has finished running, the user is logged off, and you end up with a login prompt.

1-2. running a script from vi?

you can do all of your testing and running of a script from vi. while using vi you can run any script by using :! colon exclamation command and pressing enter. and you can repeat any command that you just ran in vi by typing :!! colon exclamation, exclamation and pressing enter.

a further short cut is that the name of the current script to be edited, can be run by typing the % percent character. you can change to permissions mode by typing :! colon exclamation chmod command and change the permissions to +x make filename executable, or you can run the current file by typing :! colon exclamation %, and the file will run.

3. your path and bin?

personal scripts that are used to help automate daily routines, and are usually stored in the user's home bin directory.

example: exec /bin/ls -l A --color $* # automatically colors the assorted directories during ls.

to enable the scripts to run from anywhere in the system, the bin directory needs to be added to your path. the PATH is typically set in your .profile file. and your path is a variable that contains a list of directories separated by ":" that the shell looks into, to locate executable files in the path.

example: :~/bin:$PATH

makes the shell look into the home directory bin. the colon at the beginning of the path means to look in the current directory first, and the "~" tilde means to look in the home directory next, and then look in the PATH.

4. script interpreter?

to enable the shell to know what program should be run to interpret the script, the script interpreter may be specified on the first line of the of the script.

example: #!/bin/sh # the script interpreter may be specified on the first line of the of the script. or #!/usr/local/bin/perl # this technique of setting the shell is essential for cgi

# programming.

5. cgi scripts?

a cgi program script is a program that is used to provide interactivity, automation, or database connectivity to a web site. any type of program can be a cgi script including bourne shell scripts.

for a bourne script to act as a cgi script, it must be executable and begin with the line #!/bin/sh. the output produced by the script must be recognized as valid http, which requires that the standard output begin with Content-type: text/html.

example: #!/bin/sh

echo Content-type: text/plain # this code tells the shell to use the sh to output plain

# text of the /bin file. echo

ls /bin

1. shell programming features?

we know that the unix shell can be thought of as a programing language.

a variable is a small named pieces of memory that can be assigned "=" values. and there must be no spaces on either side of the variable=value assignment.

a variable can be thought of as a box that can contain a content of values. because a variable can contain many different values the values can change, and when a new value is added to the box the old value is lost.

variable names must be unique, no two variable names can be alike, and the name of the variable is case sensitive and can only contain the characters a-z, A-Z, 0-9, _ but cannot begin with a digit. all variables are strings. the value in the box can be just about anything.

if your value must contain spaces, you must surround the value with " " double quotes. to retrieve the value of the variable you prefix the $ dollar sign to the variable.

example: echo you live on $street. # the value of the variable street is output in place of $street.

2. environment variables?

many variables are preset, such as HOME, PATH, LOGNAME, TERM, etc. the variable may be changed but the shell script will not see the new value unless the script is invoked using the "." dot operator. the variable values will disappear as soon as you log out and the login script that you use to call the variable will see the original variable value.

when you create a new variable, the variable is not visible to the other programs and other scripts unless the variable has been added to the shell environment.

a variable is added to the environment by exporting it to the environment.

example: street="charles street" # the value charles street is assigned the variable street. export street # export, exports the variable street so that other programs # may read it.

the export variable brings the variable into the environment. and you test the variable setting with echo $. this does not mean that the variable is added to the login path, therefore it will not be seen by the login script. the line that runs the script has to be added to the login script before it will be seen by the login script, or it may otherwise be executed by adding the "." to the login path.

3. the trouble with quotes?

there are three different types of quotes available in unix, the single quote ' ', the double quote " ", and the ` back quote. you surround a piece of text by putting a quote at one end of the text and the other quote at the other end of the piece of text.

when a piece of text is surrounded by single ' ' quotes, every character in that text is considered normal non-special text, with exception of the single quote.

a space character is a parameter used to determine where the parameter of a command ends and where the next parameter begins, this includes new lines.

when a piece of text is surrounded by double " " quotes then $ the dollar sign, ' single quote and \ back slash are still treated as special characters.

4. back quotes?

any text enclosed in back quotes is treated as a unix command, and is executed in its own shell. any output from the command is substituted into the script line, replacing the quoted text.

5. grouping commands?

if you wish to apply the same actions to several commands it is possible to group the commands together using parenthesis.

example: (pwd; ls; who) # the pwd present working directory, ls list and who commands # are run as a group.

6. line control?

it is also possible to run two or more unix commands at the same time by separating them using ";" semi colon character.

7-8. exercise which is a variable name?

which of the following are valid variable names? month valid echo valid $year is a variable substitution that causes the contents of the variable to be displayed. 24_hours variables cannot start with a digit. hours-24 variables cannot contain a hyphen "-". fifty% variables cannot contain a percent sign. first name you can have a space in a variable's contents, but you cannot have a space in a variable. a valid _first_name valid winner! variables cannot contain exclamation ! marks.

create and echo out to the screen the following values: charles, charles gilberg, that's life.

name1=charles # name1 is assigned charles. echo $name1 # $name1 echoes out the value charles.

name2='charles gilberg' # using single quotes name2 is assigned charles gilberg. echo $name2 # $name2 echoes out the value # charles gilberg.

# single quotes keep the shell from manipulating the contents of the data string.

name3="that's life" # use double quotes because the value contains a single quote. echo $name3 # $name3 echoes out the value that's life.

set the variable age to 45 on the command line and then write a script to echo that value out onto the screen:

cat age_script # first created an age script. age=45 # age is assigned the value 45. echo $age

export age # export, exports the variable age so that other programs # may read it

age_script # run age_script 45

what's wrong with the following code? myname=ken echo 'hello $myname, today's date is "date %d/%m/%y"' # rap the script in double quotes because a single quote is used within the text "today's" # and rap the date in "`" back quotes within the double quoted string of text to allow the # date command to run.

on a single line of code cause the output to be sent to an instance of the more program command: today's date the current directory name the contents of the current directory and a list of the users currently logged in (date; pwd; ls; who) | more # parentheses group the commands while semicolons # are used to separate the programs on a single line.

9-10. course project?

a menu based program, offering the user options to create, view, search for and delete contact details and store the details in a text file.

the program must be fully commented and prompt the user for six pieces of data: first name, surname, address, city, state, and zip code.

this information must be appended to the end of a text file and on one line, separated by a ":" colon.

the variable that will store the name of the file must be labeled fname. but the name value of the file can be whatever you'd like.

before the program exits it must display the contents of the file as well as count the number of records in the file.

# program 1

#!/bin/sh # # the above sh causes this script to be run using the bourne shell (sh). ####################################################### # # script to maintain database. # ####################################################### # # assign the filename. # fname=names.dat # fname is assigned the value of the file names.dat.

# # read the contact details from the keyboard. # echo "please enter the following contact details:" echo echo "given name: \c" read name echo " surname: \c" read surname echo " address: \c" read address echo " city: \c" read city echo " state: \c" read state echo " zip code: \c" read code # echo reads the details from the keyboard that are given to the read command.

# # appends the details to a text file. # echo $name: $surname: $address: $city: $state: $code: >> $fname # the data is echoed out onto the screen and appended to $fname and colons separate # the data information.

# # show what is currently in the file. # ( echo echo here are the current contacts in the database: echo cat $fname # the details of the data from $fname are displayed with cat and piped page at a time # to more. ) | more

# # display how many contacts there are. # echo echo there are `cat $fname | wc -l` contacts in the database. # back quotes allow echo to run the script output within the text that is echoed out onto # the screen where the number of files from the dat file are counted.

1. conditional code?

menu driven means the user will be presented with a series of choices. depending upon their choices the program will do different things . . . create a record, delete a record etc.

whenever unix completes it returns a value to the program that started it, informing the program of the number value of the exit status of completion of the program.

true false is an exit status. an exit status of 0 zero means true that the program completed with no errors. an exit status of some other number means false that some error has occurred.

however, with the diff command the return value is 0 zero if the files being compared are identical, and 1 if one the files are different. the exit status is stored in the built in "?" variable and can be examined by using echo $?. the contents of the variable are up dated every time the program runs, including the echo program command. this is exactly the opposite in how the c program treats the true false return value. the unix true command program echoes a value of 0. the unix false program command echoes a value of 1, and these commands are useful for creating forever loops.

2. conditional and && and or || command execution?

the condition to run another program or not is always expressed in terms of the exit status of another or previously run program.

command1 && command2 # command2 will run only if command1 completes with an exit status of true 0.

example: ls file1 && cp file1 /tmp # ls list file1 and cp copy file1 to the temporary file.

example: command3 || command4 # command4 will run only if command3 completes with an exit status not of 0. # in other words, if command3 produced an error then run command4.

example: diff file1 file2 || echo the files are different # diff checks if file1 and file2 are the same, or || if the files are different echo # the files are different.

if file1 is different from file2 it returns a false status value of 1 and therefore, echoes that the files are different. or if echo has a true value of 0 the command does nothing. in this construct you cannot specify another command to run if the condition is still not met.

3. the if statement?

the and && or || limitation is remedied by the use of the if statement.

example: if command1 then # if an exit status of true 0, then proceed into the block of code. command2 # in an if statement there must be at least one command. command3 . . . fi # fi is put there so the shell knows what point to jump down to if # the command1 value turned out to be 1 false.

example: if diff file1 file2 > /dev/null then # if an exit status of 0, then proceed into the block of code. echo the files are the same rm file2 fi

4. the else clause?

the else clause is used to execute commands on the condition that a given command returns a non-zero exit status.

if command1 then one set of commands # in the else clause there must be at least one command. else # else executes another set of commands if a given condition is not met. another set of commands fi

example: if diff file1 file2 > /dev/null # diff option checks if the files are the same and sends all output to /dev/null then # if an exit status of 0, then proceed into the block of code. echo the files are the same rm file2 # if files were the same then rm removes the data and file2. else # else if exit status is 1execute the other commands because the condition was true 0 was not met. echo the files are different! echo please view the differences: diff file1 file2 # else the files were the same and diff displays the differences that were sent to file2. fi

we now have a way to execute commands if a given command returns a non-zero value.

example: if ls file1 > /dev/null # ls option checks the file and sends all output to /dev/null then : # ":" here the colon is the do nothing command we do nothing if the file exists. echo the file does not exist . . . exiting. # we echo the file and quit if the file does not exist.

fi

5. the elif clause?

the elif conditional clause is short for else if and is used when we construct code that has more than two mutually exclusive options.

if command1 then command set 1 elif command2 # do command 1 or command 2, then do command 2 or command 3. then command set 2 else command set 3 fi

example: if ls $file > /dev/null 2>&1 # ls silently lists the files and sends all output to /dev/null then echoes some text. then echo sorry the file already exists. elif who > $file # or the elif option sends the who output to > file and echoes some text echo $file now contains the user list. else # else echoes some other text. echo could not create $file. fi

you can use as many elif statements to create as many then code blocks as you want. but you can only use one else clause.

6-7. using test?

comparing two variables or comparing a variable and a value for equality, or inequality, if one is greater than or less than the other. bourne shell does not support such comparisons, but unix is able to make such comparisons using a program called test.

test changes its exit status according to whether the results of the comparison were true 0 or false 1..

example: var1=10 # assign a variable. test $var = 20 # test the variable value true 0, false 1. # you must have spaces around both sides of the "=" equal sign. echo $? 1 # the variable value comparison returns a true false exit value # status. the exit status here the exit status is extracted by $? and is false.

example: if test $var1 -gt $max # -gt means greater than the $max maximum. then echo the value is too large. fi

because the test is not an assignment, in the test $var1 = 29 you must have spaces around both sides of the "=" equal sign.

if checking the variable using test causes an error, this can be remedied by enclosing the variable in double " " quotes.

example: test "$var1" = 20

test value 1 = value 2 # returns 0 zero, true if the values are equal.

test value ! = value 2 # returns 0 true if the values are not true.

test value 1 -gt value 2 # returns true if the numeric value of value 1 is greater than # value 2.

similarly, options in -lt less than, -ge greater than or equal to, and less than or equal to -le.

test value with no parameters returns true zero 0 if the value is non-empty. test value -z returns a value of true if the value is empty.

test -f filename returns a zero 0 value of true if the file exists as a regular file.

test -d filename returns a zero 0 value of true if the given file exists as a directory.

test -s filename returns a zero 0 value of true if the given file has a file size greater than 0 zero.

test -r|w|x filename returns a true value of 0 zero if the given file exists and is readable | writable | and or executable by the current process.

8. test ! not?

you can test if a file is not readable writable and executable by test ! -r|w|x filename returns a true value of 0 zero if the given file exists and is not readable | writable | and or executable by the current process, cause the test ! not returns 0 true if the expression is false.

test -a and is used to test the expressions of two files.

example: echo "please enter a filename: \c" read filename

if test -z "$filename" # test -z to see if a filename was entered. then echo you did not enter a filename. elif test -f "$filename" -a -w "$filename" # test -f for file and -a for and -w writable # returns 0 true if both are true. then echo every thing is fine. else echo the file is not a writable file. fi

test -o is the test or option returns 0 true if one of the other expressions are true.

test has an alias which is the open square bracket [.

example: if [ $var1 -gt $max ] # test [ to see if the variable is greater than the max. if you use the open square bracket # test, you must close the expression with a closing square bracket.

then echo that value is to large. fi

example: echo "please enter a filename: \c" read filename

if [ -z "$filename" ] # test [ -z to see if a filename was entered. then echo you did not enter a filename. elif [ -f "$filename" -a -w "$filename" ] # test [ -f for file and -a for and -w writable # returns 0 true if both are true. then echo every thing is fine. else echo the file is not a writable file. fi

9. the case statement?

the case statement eliminates the use for elif then statement.

example: case $val1 in val1) # the decision is chosen from the ")" parenthesis control expression. code for case 1 ;; # the double semicolon serves as a break command # which gets out of the case loop. val2) code for case 2 ;; val3) code for case 3 ;; val4) code for case 4 ;; esac

case example: echo "please enter a rock group name \c" read rname

case $rname in beatles) no_albums=12 last_album="let it be" ;; "dire straights") no_albums=7 last_album="on every street" ;; abba) no_albums=6 last_album="abba gold" ;; esac echo $rname made $no_albums albums. the last one was called \"$last_album\" # \ delimits the double quotes in the string and prints them out and allows the $ # variable to run.

the *) asterisk case is used to run if the value of var1 did not match any of the cases.

example: case $var1 in val1) code for case 1 ;; . . . *) code for any case that is not covered above. ;; esac

*) example: echo "please enter a rock group name \c" read rname case $rname in beatles) no_albums=12 last_album="let it be" ;; "dire straights") no_albums=7 last_album="on every street" ;; abba) no_albums=6 last_album="abba gold" ;; *) # the *) asterisk case is used to run if the value of var1 did not # match any of the cases. echo unknown rock group. exit

esac echo $rname made $no_albums albums. the last one was called \"$last_album\" # \ delimits the double quotes in the string and prints them out and allows the $ # variable case for the assignment of last_album to run within the quotes.

pipe | example: echo "please enter a rock group name \c" read rname

case $rname in beatles|"the beatles") # pipe | allows for many different cases for the same code including wildcards. no_albums=12 last_album="let it be" ;; "dire straights") no_albums=7 last_album="on every street" ;; abba) no_albums=6 last_album="abba gold" ;; *) # the *) asterisk case is used to run the echo the echo if the value of var1 did not # match any of the cases. echo unknown rock group. exit

esac echo $rname made $no_albums albums. the last one was called \"$last_album\" # \ delimits the double quotes in the string and prints them out and allows the $ # variable case for the assignment of last_album to run within the quotes.

wildcards example: echo "please enter a rock group name \c" read rname

case $rname in [bB]eat*|"the beatles") # the any wildcard allows for many different cases for the same code.

no_albums=12 last_album="let it be" ;; "dire straights") # the " " double quotes are used to group a string of multiple words. no_albums=7 last_album="on every street" ;; abba) no_albums=6 last_album="abba gold" ;; *) # the *) asterisk case is used to run the echo if the value of var1 did not match any of the album # cases.

echo unknown rock group. exit

esac echo $rname made $no_albums albums. the last one was called \"$last_album\" # \ delimits the double quotes in the string and prints them out and allows the $ # variable case for the assignment of last_album to run within the quotes.

syntactically, there are many language elements to remember to get the case statement right: case # begin case. in # the selection mechanism. esac # end case. ) # the decision is chosen from the ")" control expression. ;; # the double semicolon serves as a break command which gets out of the case. | # pipe | allows for many cases for the same code including wildcards. wildcards # allows for a varied selection of characters to be typed in # for the decision choice.

10-11 exercise?

write a script that asks a user for their age, then compares that age to a variable called retirement_age. print out a message telling them that they should be retired. otherwise tell them that they are still young. make sure the case can handle if the user doesn't type in an age and simply presses enter.

retirement_age=65 echo "please enter your age: \c" read age

if [ "$age" = "" ] # the empty quote case that handles if the user doesn't type in an age. then echo you did not enter an age. elif [ $age -gt retirement_age ] # test command to see if they are older than the value of age. then echo you should be retired. else echo you are still quite young. fi

write a script that reads the name of a directory from the keyboard and then checks to see if the name is indeed a directory that can be written to. if all is ok the script should create a file in a given directory called hello.

echo "please enter a directory name: \c" read dname if [ "$dname" = "" ] # test to see if the file is a directory. then echo you did not enter a directory elif [ -d $dname -a -w $dname ] # test to see if the file is a directory -a and -w writable and if the parameter is empty. if true well done # echoes and create the directory hello. then echo well done! > $done/hello else echo $done is not a writable directory - nothing written. # else not a directory and not writable. fi

modify the contacts database script to present the user with a menu of choices, 1. create a record, 2. view the record, # view the record without creating a record, 3. search for records, 4. delete a record that matches a certain pattern. ensure that the script can handle any invalid input from the user.

# program 2

#!/bin/sh # # the above sh causes this script to be run using the bourne shell (sh). ####################################################### # # script to maintain database. # ####################################################### # # assign the filename. # fname=names.dat # fname is assigned the value of the file names.dat.

# # if the file ! does not exist, create > it. # [ ! -f $fname ] && > $fname # test to see if the file is not a file that exists, and creates a file if the file does not exist.

# # display the menu. # clear # clear causes the screen to be cleared before the menu is displayed.

echo "\n\t\tshell programming database." # \n newline \t tab echo "\t\t\tmain menu" echo "\nwhat do you wish to do?" echo "\t1. create records." echo "\t2. view records." echo "\t3. search for records." echo "\t4. delete records that match a pattern." echo # echo reads the details from the keyboard that are given to the read command.

# # prompt for an answer. # echo "answer? \c" read ans junk # function call reads the answer, to quit is selected hear anything else gets sent to junk

# # decide what to do. # case "$ans" in # "$ans" in tests if they entered anything. 1) # # read the contact details from the key board. # echo "please enter the following contact details:" echo echo "given name: \c" # note the alignment of \c to create output in columns. read name echo " surname: \c" read surname echo " address: \c" read address echo " city: \c" read city echo " state: \c" read state echo " zip code: \c" read code

# # >> append the details to a text file. # echo $name: $surname: $address: $city: $state: $code: >> $fname # the data is echoed out onto the screen and appended to $fname and colons separate # the data information.

;; # the double semicolon serves as a break command which gets out of the case loop.

2) # # show what is currently in the file. # ( echo echo here are the current contacts in the database: echo cat $fname ) | more

# # display how many contacts there are. # echo echo there are `cat $fname | wc -l` contacts in the database. # back quotes allow echo to run the script output within the text that is echoed out onto # the screen where the number of files from the dat file are counted.

;; 3) echo that search case is not implemented yet. ;; 4) echo that delete case is not implemented yet. ;; *) echo that was an invalid choice^G. # ^G is the bell character. ;; esac

1. loops?

bourne supports the for loop and the while loop.

the while loop repeats a block of code the same way the if statement conditionally executes a block of code.

while command # while command continues to return a value of 0 zero then execute the next command.

do block of code done

example: read answer while [ "$answer" != chickens ] # test to see if the answer is not chickens then echo some text.

do echo that answer is incorrect. # do block of code. echo please try again. read answer done

example: echo "please enter the name of a directory: \c" read dir

while [ ! -d "$dir" ] # test to see if name is not ! a -d directory then echo some text.

do echo "$dir is not a directory." echo "please try again: \c" # echo the directory name in the text from read dir command.

read dir done

echo "congratulation: $dir is a directory!"

it is possible to use a while loop to process each line of the output command.

example: who | while read user term time do echo $user has been on $term since $time # who the users are and the terminal they're on, and the amount of time they were on.

done

2. break and continue?

the break and continue statement are used to control the execution of the while loop. break is used to terminate the body of the loop. continue will cause the loop to abandon the current iteration of the loop and begin the next iteration of the loop, and the program retests the loop for a return exit status of true 0 or false 1.

example: while [ "$filename" ] # while testing to see if the file is a filename do the following. do if [ ! -d $filename ] # test to whether the filename is not ! a -d directory. then echo must be a directory. # if the file is not a directory echo the text. continue # the loop continues past fi to ls the file name as long as the filename variable does # not change. fi if [ `ls $filename | wc -l` -gt 100 ] # now, test file to see if the wc word count of lines in the file are greater than 100. a wc greater # than 100 changes the filename variable and breaks out of the loop.

then echo stopping - that must be a huge directory break fi # if we make it past the continue statement and the break statement we process # the directory.

read file done

3. numerical calculation?

in unix calculations are performed with the use of the expr command. you must have spaces around the expr expression. in multiplication you would use a delimiter such as back slash \*.

example: a=15 b=3 # this does not assign the value of $a / $b to perform the calculation. expr $a / $b 5

c=`expr $a / $b` # this assigns the value of $a / $b to perform the calculation where c is the sum. echo $c 5

example: read count i=1 # i is initialized to 1. while [ $i -le $count ] # test the i value to the count value. do echo this is loop $i of $count. i=`expr $i + 1 ` # the i expression is incremented by +1 each time through the loop.

done

4. the for loop?

the for loop causes a variable to be set to a given sequence of values. and then it executes that block of code once for each value.

example: for var1 in bread meat dairy vegetables fruit # each time through the loop $var1 echo one word value bread, meat, dairy, vegetables, fruit from the line.

do echo one of the main food groups is $var1 done

example: for fname in *.txt # the for loop will check each of the any dot *.txt files one by one. do [ -s $fname ] && cp $fname backsups # if fname -s size is non zero 0 it is # copied to the backups file. done

5-6. exercise?

create a script that examines all files in the current directory and displays a sum of all file sizes for each file that contains the word "foo".

pattern=foo # set the pattern to foo.

total=0 # initialize total to 0 zero.

for f in * do [ ! -f $f ] && continue # check if the file is a regular file and continue.

if grep $pattern $f > /dev/null # without displaying its findings grep returns true if the file contains the pattern. then size=`cat $f | wc -l` total=`expr $total + $size` fi done

echo the total size of all files containing $pattern is $total. # the wc from the data search is extracted by the $ assignment and displayed on screen.

modify the course project so that the main menu is redisplayed after each action, until the user types "q".

# program 3

#!/bin/sh # # the above sh causes this script to be run using the bourne shell (sh). ####################################################### # # script to maintain database. # ####################################################### # # assign the filename. # fname=names.dat # fname is assigned the value of the file names.dat.

# # if the file ! does not exist, create > it. # [ ! -f $fname ] && > $fname # test to see if the file is not a file and output to fname. # test to see if the file is not a file that exists, and creates a file if the file does not exist.

# # loop forever - loops the display menu until the user wants to exit the program. # while true # if the exit value is true 0 do menu display.

do

# # display the menu. # clear # clear causes the screen to be cleared before the menu is displayed.

echo "\n\t\tshell programming database." # \n newline \t tab echo "\t\t\tmain menu" echo "\nwhat do you wish to do?" echo "\t1. create records." echo "\t2. view records." echo "\t3. search for records." echo "\t4. delete records that match a pattern." echo # echo reads the details from the keyboard that are given to the read command.

# # prompt user for an answer from the selection 1 - 4 or quit. # echo "answer (or 'q' to quit)? \c" # enter q to quit running the program. read ans junk # function call reads the answer, to quit is selected hear anything else gets sent to junk

# # empty answers (pressing enter) causes the menu to redisplay, # so we go back around in the loop # we only make it to the continue program if the test # program "[" returned 0 true # ["$ans" - "" ] && continue # check if the ans is empty and continue to case selections 1 - 4 or quit.

# # decide what to do. # case "$ans" in # "$ans" if they entered anything. 1) # # read the contact details from the key board. # echo "please enter the following contact details:" echo echo "given name: \c" # note the placement of \c to create columns. read name echo " surname: \c" read surname echo " address: \c" read address echo " city: \c" read city echo " state: \c" read state echo " zip code: \c" read code

# # >> append the details to a text file. # echo $name: $surname: $address: $city: $state: $code: >> $fname # the data is echoed out onto the screen and appended to $fname and colons separate # the data information.

;; # the double semicolon serves as a break command which gets out of the case.

2) # # show what is currently in the file. # ( echo echo here are the current contacts in the database: echo cat $fname ) | more

# # display how many contacts there are. # echo echo there are `cat $fname | wc -l` contacts in the database. # back quotes allow echo to run the script output within the text that is echoed out onto # the screen where the number of files from the dat file are counted.

;; 3) echo that search case is not implemented yet. ;; 4) echo that delete case is not implemented yet. ;; q*|Q*) # q*|Q*) q any character condition to quit. exit 0 # no error exit status. ;; *) echo that was an invalid choice^G. # ^G is the bell character. ;; esac

# # pause to give the user a chance to see what option he selected. # echo "hit to continue: \c" read junk done

1. text processing?

text processing programs is done by a class of filters. this is done when we need to analyze the text that is produced by a program or we may need to present this text to a user in a user friendly way.

a filter is a unix command line program that takes standard input and performs some processing on the data it receives from either file or the keyboard, and produces output as a result of the input it received.

wc is a filter because the processing it does on data is counting lines words and characters, and outputs the count of that particular input.

ls is not a filter because it does not take input.

cat does not process data, instead it takes input and echoes it back out onto the screen.

more paginates data out to the screen one page at a time.

grep is used for the removal of lines that do not contain certain requested text.

sort sorts the information alphabetically, but it does not modify the file.

tee takes its input duplicates it, and writes it to two places.

example: who | tee wholist | wc -l

who | pipes output to tee which sends its input as output to the wholist file and also | pipes that output to wc word count which lists the lines -l of who is logged in on the server.

sed is a basic editor.

example: who | sed "s:pts/: terminal: "

sed searches who is logged on the server and substitutes pts/ with the word terminal.

and example: who | sed /may/d

displays who is logged on the server and d removes all instances of may.

awk can process anything and supports its own scripting language.

2. grep?

grep performs processing on input for either the keyboard, a file or another program, and displays lines of text from its input that contain a certain pattern. put another way grep removes lines of text that does not contain a certain pattern.

example: grep pattern [files]

grep sincerely *.txt # grep searches for all instances of sincerely in any text files.

who | grep root # here grep would show the instances where root is logged on.

3. regular expressions?

grep stands for global regular expression parser. a regular expression is a term used to describe a set of special text matching patterns.

example: ^abc # matches any pattern that begins with abc.

grep '^abc' file # matches patterns in the file that begin with abc.

grep abc file # matches the abc pattern anywhere in the file.

grep '/sh$' file # matches any line of text that ends with /sh.

grep '^$' file # matches a line that begins and ends with nothing, a blank line.

grep 'ca*t' file # matches the amount of a's in a file from none to any.

grep 'a+' -E file # -E extended expression matches any sequence of a's from # one or more.

grep c[ou]t file # matches any single o or u between c and t in the file.

grep c[ou]*t file # matches every and any amount of o or u's between c and t in the file.

grep c*t file # matches any character between c and t in the file.

for more regular expressions check the man pages for grep or regexp. grep, sed, awk, vi and line based editors ed and ex.

4. sort?

sort is a filter whose process consists of sorting lines of text from input received from a file program or keyboard.

example: sort database or who | sort

do not make this mistake when manipulating files: sort file1 > file1. this will give you an empty file because it erases the data in file1, before > outputting the data in file1. the correct technique would be: sort file1 > file2, then mv file2 file1.

5. sed?

sed short for stream editor is a program for performing basic editing tasks on the output of another program or file. remember to enclose the sed actions in ' single quotes.

the basic form of sed is: sed action [files]

sed can perform several actions at the same time: sed -e action1 -e action2 [files] sed -f scriptfile [file]
# sed will open up the scriptfile and perform all the actions of the script in the file.

example: sed 's/bash/sh' homefile
# sed substitutes the first occurrence bash with sh on each line in the homefile.

sed -e 's/bash/my sh' -e s/false/error homefile
# sed substitutes bash shell with my sh shell and false with error in the homefile.

sed s/bash/sh/g homefile # g changes all occurrences of bash to sh in the homefile.

sed 1, 10s/bash/sh/ homefile # substitutes lines 1 through 10 with sh in the homefile.

sed 40, $s/bash/sh/ homefile # substitutes lines 40 to the $ last line from bash to sh in the homefile.

sed 11, 20/d homefile # deletes lines 11 through 20 in the homefile.

sed '/bash/d' homefile # deletes all instances of bash in the homefile.

sed '99, $!d' homefile # deletes from line 99 but does not the delete $ last line.

sed '/bash/!d' homefile # does not delete the instances of bash.

creating a sed script example: #!/bin/sed -f # because the program opens in sed, sed does not need to be invoked on the # command line. # # this script will be run using the sed program. # s/nameidonotwant/nameiwant/ # this sed script substitutes the name i do not want with the name i want.

/removename/d # this sed script removes name.

6-7. awk?

awk aho weinberger and kernighan, is a text processing tool and programming language.

the basic form of awk is: awk action [files]

in awk the action is a sequence of statements enclosed in { } braces each separated by ; semicolons. remember to enclose the awk actions in ' single quotes.

in awk each parameter is made up of numbered tokens $1, $2, $3, etc., which are the line's tabs and spaces. a parameter is an ordered sequence.

example: $# # $# identifies the parameter count. $ @ # $@ gives the identity of all parameters. $ - # identifies the parameter flags. flags are useful in debugging because it forces # the shell to echo each command it finds.

example: who | awk '{print $1, "is on terminal", $2}' # awk prints the user in $1 and some text and the terminal $2 the user is on.

-F option is used to specify the character used to separate tokens.

example: awk -F : '{print $1, "home dir is", $6}' /etc/passwd # -F specifies the : field separator and awk prints the user $1 and their home $6.

it is possible to perform different actions on lines that match certain regular expression patterns.

example: awk '/australia/ {print $1}' filename # causes australia to be printed out in the user $1parameter.

it is possible to perform arithmetic on variables within awk.

example: awk '{print $1, ($3+$4)/$5}' filename # adds parameters 3 and 4 and divides it by the 5th parameter of filename.

a complex set of actions may be put in a separate script file and executed on another file.

example: awk -f scriptfile filename

it is also possible to create a standalone script file to process another file.

example: #!/bin/awk -f # awk -f causes awk to look in a file type. BEGIN { FS = ':' # FS is initialized to : colon.

} { printf("%s, home dir %s\n", $1, $6) # prints the quoted the string home and dir in the $1 user parameter and $ 6 home parameter. }

example: #!/bin/awk -f # awk -f causes awk to look in a file type. BEGIN { FS = ":"; # FS is initialized to : colon and ; semi colon. printf("username directory\n"); printf("==========================\n"); # these two lines are printed out only once. } { printf("%-12s%-20s\n", $1, $6) # %-12s gives username $1 a width of 12 spaces and %- 0s gives directory $6 a width of 20 spaces. }

8-9. exercise?

create a script that uses grep to find all occurrences of the pattern in the greptest file. grep for lines that start with a, t. grep for blank lines. grep for lines that have two or more a's anywhere in them. grep for lines that have two or more digit numbers in them. grep for lines that have the pattern square bracket [x, y] with the numeric values x and y in them.

file=greptest

echo lines that start with a, t. grep '^t' $file echo ====================== # lines that start with a, t.

echo blank lines grep '^$' $file echo ====================== # blank lines.

echo lines that have two or more a's anywhere in them. grep 'aa' $file echo ====================== # lines that have two or more a's anywhere in them.

echo lines that have two or more digit numbers in them. grep '[0-9][0-9]' $file or grep -E '[0-9]{2,}' $file # 2 with the , comma and nothing after it indicates two or more digits. echo ====================== # lines that have two or more digit numbers in them.

echo lines that have the pattern square bracket [x, y] with the numeric values x and y in them. grep -E '\[[0-9]+,[0-9]+\]' $file echo ====================== # lines that have the pattern square bracket [x, y] with the numeric values x and y in them.

write a script that reads data from the who program that alphabetically list the user and the date and time.

who | sort | awk '{printf(%-15s%s %2s %s\n", $1, $3, $4, $5)}' # the formatting of the s strings is placed within the $ parameters.

modify the project so that the lines in names.dat are printed out neatly without : colons and in surname order.

# program 4

#!/bin/sh # # the above sh causes this script to be run using the bourne shell (sh). ####################################################### # # script to maintain database. # ####################################################### # # assign the filename. # fname=names.dat # fname is assigned the value of the file names.dat.

# # if the file ! does not exist, create > it. # [ ! -f $fname ] && > $fname # test to see if the file is not a file that exists, and creates a file if the file does not exist.

# # loop forever - until the user wants to exit the program. # while true # if the exit value is true 0 do menu display.

do

# # display the menu. # clear # clear causes the screen to be cleared before the menu is displayed.

echo "\n\t\tshell programming database." # \n newline \t tab echo "\t\t\tmain menu" echo "\nwhat do you wish to do?" echo "\t1. create records." echo "\t2. view records." echo "\t3. search for records." echo "\t4. delete records that match a pattern." echo # echo reads the details from the keyboard that are given to the read command.

# # prompt for an answer. # echo "answer (or 'q' to quit)? \c" # enter q to quit running the program. read ans junk # function call reads the answer, to quit is selected hear anything else gets sent to junk

# # empty answers (pressing enter) causes the menu to redisplay, # so we go back around in the loop # we only make it to the continue program if the test # program "[" returned 0 true # ["$ans" - " " ] && continue # test if the ans is empty and continue.

# # decide what to do. # case "$ans" in # "$ans" if they entered anything. 1) # # read the contact details from the key board. # echo "please enter the following contact details:" echo echo "given name: \c" # note the placement of \c to create columns. read name echo " surname: \c" read surname echo " address: \c" read address echo " city: \c" read city echo " state: \c" read state echo " zip code: \c" read code

# # >> append the details to a text file. # echo $name: $surname: $address: $city: $state: $code: >> $fname # the data is echoed out onto the screen and appended to $fname and colons separate # the data information.

;; 2) # # show what is currently in the file. # ( echo echo here are the current contacts in the database: echo echo "first name surname address city zip code" echo "============================================"

# # display the line correctly formatted. # use awk for the formatting. # the "-F :" causes awk to perceive fields to be separated by : colon. # "%14. 14s" displays a string in a string field width of 14 left justified. # # sort -t : causes the shell to perceive fields to be separated by : colon and +1 # specifies the second field which is the surname field. # sort -t : +1 $fname | awk -F : '{printf("%-14. 14s%-16. 16s%-20. 20s%-15. 15s%-6. 6s%-5. 5s\n", $1, $2, $3, $4, $5, $6)}' # the formatting of the s strings is placed within the $name $surname $address $city # $state and $code parameters, and piped to more.

) | more # # display how many contacts there are. # echo echo there are `cat $fname | wc -l` contacts in the database. # back quotes allow echo to run the script output within the text that is echoed out onto # the screen where the number of files from the dat file are counted.

;; 3) echo that search case is not implemented yet. ;; 4) echo that delete case is not implemented yet. ;; q*|Q*) # q*|Q*) condition to quit. exit 0 # no error exit status. ;; *) echo that was an invalid choice^G. # ^G is the bell character. a bell rings if an invalid choice is selected. ;; esac

# # pause to give the user a chance to see what option he selected. # echo "hit to continue: \c" read junk done

1. functions - program structure?

interpreter specification, the program used to interpret the script. opening comment that describes what the script does and how to use it. important variables, setting of that variable, determines the value of that variable that is put in function call from the main body of code.

example: #!/bin/sh # interpreter specification is set to sh. ################################# # program to backup a directory ################################# dir=home/user1/docs # important variables are assigned to dir. backupdir=/backups/user1 # setting of that variable is assigned to the action to backup.

backup_one_file() # the function call is where the value of that variable is put, after it has been set. { cp $1 $backupdir # functions. the parameter is copied into $1. echo $1 has been backed up. }

for file in $dir/* # the main body of code. do [ -s $file ] && backup_one_file $file # -s tests the size of the file and the variable is set to $file before it backs up the file.

done

2. defining and calling a function?

a function is a named code block that can be run from any point in the program by invoking its name.

a function must be defined: function_name() # the () parentheses tell the shell that you are declaring a new function within the body # of code and the name prefixed to the parenthesis identifies the name of the function # call that the value is returned to.

{ code block # the code block gets executed. . . . }

the code block does not get executed until and unless the function gets called.

example function call: file=greptest

pause() # function is defined as a call to pause that has been set within the body of code. { echo "hit the to continue: \c" read junk }

echo lines that start with a, t. grep '^t' $file pause # function is set to call pause.

echo ====================== # lines that start with a, t.

echo blank lines grep '^$' $file pause # function is set to call pause. echo ====================== # blank lines.

echo lines that have two or more a's anywhere in them. grep 'aa' $file pause # function is set to call pause.

echo ====================== # lines that have two or more a's anywhere in them.

echo lines that have two or more digit numbers in them. grep '[0-9][0-9]' $file or grep -E '[0-9]{2,}' $file pause # function is set to call pause.

# and the 2 with the , comma and nothing after it indicates two or more digits. echo ====================== # lines that have two or more digit numbers in them.

echo lines that have the pattern square bracket [x, y] with the numeric values x and y in them. grep -E '\[[0-9]+,[0-9]+\]' $file pause # function call to pause.

echo ====================== # lines that have the pattern square bracket # [x, y] with the numeric values x and y in them.

write a script that reads data from the who program that alphabetically list the user and the date and time.

who | sort | awk '{printf(%-15s%s %2s %s\n", $1, $3, $4, $5)}' # the formatting of the s strings is placed within the $ parameters.

modify the project so that the lines in names.dat are printed out neatly without : colons and in surname order.

3. function parameters?

it is possible to give a function a piece of data on its command line and that function can use that data in its processing, and the data that you specify on the command line is called a function parameter. function parameters are used similar to program parameters, in that function parameters modify the behavior of the function.

there are nine, $1 through $9 possible parameters that can be individually referenced for one function, but you can reference any one parameter that you'd like. in the shell there is no parameter checking done.

variables are created for us by the shell, $* identifies the value of all the parameters, $# identifies the specific number count of parameters.

the for loop can be written in such a way that it will loop for each specified parameter.

backup_these_files() # the () parentheses tell the shell that you are declaring a new function, *.dat gets put in the parentheses. { for fname # short for "for fname in $*", any filename and looks for a file name in all the parameters. do cp $fname /tmp # copy cp $fname to temp. echo $fname has been backed up. done } backup_these_files *.dat # in the function parameter *.dat is set as the return value. data that gets backed up returns true 0 and if # no data is backed up false 1 is returned.

4. function return value?

a function can return a value in two ways, standard output and an exit status.

the function output is all the combined output of all the programs that produce output that are run within the code block of the function, e.g. who, ls, echo, etc.

this output may be sent to: sample_function | wc -l # pipes output to another program. sample_function > file1 # sends output to a file. output=`sample_function` # sample_function value is stored in the variable output.

if you do not specify an exit status for your function, the exit status of the last command that function executes becomes the exit status.

an exit status may also be specified by using the return statement and a number, 1 returns a value of false, 0 returns a value of true.

example: valid_file() { [ ! -r $1 ] && retrun 1 # test to see if the file is not -r readable, and return 1 false. grep LOGFILE $1 > /dev/null || return 1 # grep for logfile if logfile does not exists return 1, if logfile does exists return 0. }

both the exit statement and the return statement take an optional parameter, a number that represents an exit status that is returned to the calling environment. but the exit statement and return statement should not be confused.

the exit statement terminates the execution of the current shell, and when that shell terminates the user is left back at their login shell.

the return statement terminates the execution of the current function.

5. functions in other files?

functions that you write and may want to reuse, may be placed in a separate file and included in the function of other scripts that you write by using the "." command.

example: . /home/user1/libs/script_library1

6. yesno function?

# # yesno() # # a function to display passing a string as in the preceding $* any parameter, followed by a "(y/n)?", # and then asks the user for either a yes or no answer, and excepts nothing else. # if yes is answered, return an exit status of 0 true. # if no is answered, return an exit status of 1 false. # yesno() { # # loop until a valid response is entered. # while : # : colon returns a value of zero 0 and means while true. do # # display the strings/parameters passed in, followed by "(y/n)?" # the \c causes suppression of the echo's new line, and causes the cursor_ # to be place on the same line as the \c. # echo " $* (y/n?) \c" # $* means all the words that make up the (y/n) question.

# # read the answer - only the first word of the answer will # be stored in "y/n" the rest will be discarded # courtesy of junk. # read junk

case $yn in y|Y|yes|Yes|YES) return 0;; # return true. n|N|no|No|NO) return 1;; # return false. *) # in a case where any answer other than yes or no is answered. echo please answer yes or no.;; # # and continue the loop. # esac done }

how to reuse the yesno function from another file by using the "." command.

example: . function_library # # test yesno function. # while true do if yesno do you really wish to quit now. # yes exit value is 0 true and no exit value # is 1 false. then exit fi done

7-8. exercises?

write a function that calculates the average of all its parameters and prints the average to standard output. make sure that you handle the case where no parameter is given.

average() ( if [ $# = 0 ] # test the specific number count of the parameter if no parameter # is given print out 0. then echo 0 return fi total=0

for i # i is initialized to $* any parameter. do total=`expr $total + $1` # the assignment calculates the total of parameters and gives an addition of # parameters by $1 into the total per parameter.

done

expr $total / $# # the total of parameters is divided by each group of parameters. )

echo the average of 4 8 and 21 is `average 4 8 21` # function call to average. echo the average of 4 and 14 is `average 4 14` echo the average of nothing is `average`

modify the project, make sure that the code block that gets executed for the menus options is a function. copy and paste the yesno function into your script. use it to confirm that the user wants to exit the program when they type q. confirm the addition of each record by showing the user what they are about to add. after each record has been added ask the user if they would like to add another record. create a pause function and call after each menu option completes.

# program 5

#!/bin/sh # # the above sh causes this script to be run using the bourne shell (sh). ####################################################### # # script to maintain database. # ####################################################### # # assign the filename. # fname=names.dat # fname is assigned the value of the file names.dat.

# # pause() # # ask the user to press and wait for them to do so. # pause() # function call to pause. { echo "hit to continue: \c" read junk }

# # yesno is a function to display a string passed in as $* any parameter, # followed by "(y/n)?", and ask for either a yes or no answer. nothing else is acceptable. # # if the answer is yes, yesno returns an exit status of 0 (true) # if the answer is no, yesno returns an exit status of 1 (false) # yesno() # function call to yesno. { # # loop until a valid response is entered. # while : # : colon returns a value of zero 0 and means while true. do # # display the strings/parameters passed in, followed by "(y/n)?" # the \c causes suppression of echo's new line, and causes the cursor_ # to be placed on the same line as the \c. # echo " $* (y/n?) \c" # $* any parameter means all the words that make up the y/n question.

# # read the answer - only the first word of the answer will # be stored in "y/n", the rest will be discarded # courtesy of junk. # read junk

case $yn in y|Y|yes|Yes|YES) return 0;; # return true. n|N|no|No|NO) return 1;; # return false. *) # in a case where any answer other than yes or no is answered. echo please answer yes or no.;; # # and continue the loop. # esac done }

# # do_create() # # create records for our database. # do_create() # function call to create.

{ # # loop until the user is sick of entering records. # while : # first while loop requests the contact details. do

# # inner loop. loop until the user is satisfied with this one record. # while : # second while loop displays the contact details that were requested. do

# # read the contact details from the keyboard. # clear # clear causes the screen to be cleared before the menu is displayed.

echo "please enter the following contact details:" echo echo "given name: \c" # note the placement \c to create columns. read name echo " surname: \c" read surname echo " address: \c" read address echo " city: \c" read city echo " state: \c" read state echo " zip code: \c" read code # echo reads the details from the keyboard that are given to the read command.

# # now confirm. # clear

echo "you entered the following contact details:" echo echo "given name: $name" echo " surname: $surname" echo " address: $address" echo " city: $city" echo " state: $state" echo " zip: $zip" # note that zip and code are the assigned values. echo

if yesno are these details correct # yes exit value is 0 true and no exit value is 1 false. then

# # enter the details to the end of the file, # with the fields separated by colons, and # break out the inner loop # echo $name: $surname: $address: $city: $state: $zip: >> $fname # the data is echoed out onto the screen and appended to $fname and colons separate # the data information.

break # otherwise we go back through while the loop, if not we are done. fi done

# # ask the user if they wish to create a new record. # the "break" will only be executed if the user answers "no", then we are done. # yesno create another record || break # yes exit value is 0 true and no exit value is 1 false. done }

# # do_view() # # display all records in the file, complete with headings, # sorted one page at a time. # do_view() # function call to view.

{ clear

echo echo here are the current contacts in the database: echo echo "first name surname address city zip code" echo "============================================" # # display the line correctly formatted. # use awk for the formatting. # the "-F :" causes awk to perceive fields to be separated by : colon. # "%14. 14s" displays a string in a string field width of 14 left justified. # sort -t : causes the shell to perceive fields to be separated by : colon and +1 # specifies the second field which is the surname field. # sort -t : +1 $fname | awk -F : '{printf("%-14. 14s%-16. 16s%-20. 20s%-15. 15s%-6. 6s%-5. 5s\n", $1, $2, $3, $4, $5, $6)}' # the formatting of the s strings is placed within # the $ parameters. ) | more # # display how many contacts there are. # echo echo there are `cat $fname | wc -l` contacts in the database. # back quotes allow echo to run the script output within the text that is echoed out onto # the screen where the number of files from the dat file are counted.

} # # do_search() # do_search() # function call to search.

{ echo the search case is not implemented yet. }

# # do_delete() # do_delete() # function call to delete.

{ echo the delete case has not been implemented yet. }

# # start main menu. data is displayed and manipulated here. #

# # test if the file does not exist, create it. # [ ! -f $fname ] && > $fname

# # loop forever, until the user wants to exit the program. # while true # if the exit value is true 0 do menu display.

do

# # display the menu. # clear # cause the screen to be cleared before the menu is displayed. echo "\n\t\tshell programming database." # \n newline \t tab echo "\t\t\tmain menu" # function calls are selected from the menu. echo "\nwhat do you wish to do?" echo "\t1. create records." echo "\t2. view records." echo "\t3. search for records." echo "\t4. delete records that match a pattern." echo

# # prompt for an answer. # echo "answer (or 'q' to quit)? \c" # enter q to quit running the program. read ans junk # function call reads the answer, to quit is selected hear anything else gets sent to junk

# # empty answers, pressing enter causes the menu to redisplay, # so we go back around the loop. # we only make it to the "continue" bit if the "test" # program "[" returned 0 true. # [ "$ans" = "" ] && continue # test empty answer to redisplay the menu selection.

# # decide what to do. # case $ans in 1) do_create;; # create is returned to create function call. 2) do_view;; # view is returned to view function call. 3) do_search;; # search is returned to search function call. 4) do_delete;; # delete is returned to delete function call. q|Q*) if yesno "do you really wish to exit" # yes exit value is 0 true and no exit value is 1 false. then exit # if q|Q is selected exit menu. fi ;;

*) echo "please enter a number between 1 and 4^G" # any non case selection rings ^G bell, and echo demands the user select a case. # if we get here a case was not entered from the selection. ;; esac

# # pause to give the user a chance to see what is on the screen. # pause done

1. command line parameters?

any unix command can receive parameters via the command line. the command line parameters are made available to the shell programmer through the $1 through $9 variables. $1 though $9 are read only and are used the same way they are used in a function. and $* any parameter and $# specific parameter count number are used the same way they are used in functions too.

example: if [ "$1" ] # tests to see if, a parameter of the $1 was set at the command line. then echo parameter number 1 is \" $1\" # echo out the value in parameter $1. else echo parameter 1 was not set. fi

if [ "$2" ] then echo parameter number 2 is \" $2\" # echo out the value in parameter $2. else echo parameter 2 was not set. fi

if [ "$3" ] then echo parameter number 3 is \" $3\" # echo out the value in parameter $3. else echo parameter 3 was not set. fi

you can pass in any information to the parameter from the command line, such as a file name or a sentence, but with a sentence you must remember to rap that sentence in double quotes.

example: count=1 # adds and counts the parameters. for p # for loops though each parameter. do echo parameter number $count is \"$p\" count=`expr $count + 1` done

example: do_nothing() { echo the function parameters are $1 and $2. }

do_nothing xxx yyy # the xxx and yyy are put in the function call parameters $1 and $2.

echo the shell parameters are $1 and $2.

outputs: the function parameters are set to xxx and yyy. and the shell parameters are aaa and bbb. # aaa and bbb were put in function call parameters from the command line.

to make sure the scripts output is more readable, give each of the $variables a name so that their output is distinguishable.

2. advance command line control?

it is possible to reference individual command line parameters beyond $9 by using the shift command. but because the original value is lost when shifted, either use the original value before shifting, or store the value in another variable. what happens is that $1 assumes the value of the second parameter, $2 assumes the value of the third parameter, and this goes all the way down to the tenth parameter.

example: print_parms() { count=1 # adds and counts the parameters. for p # for loops though each parameter. do echo parameter number $count is \"$p\" count=`expr $count + 1` done } print_parms $* # calls the print_parms() parameter function and passes it $* which is every parameter.

echo shifting! shift

print_parms $*

it is also possible to specify that shift move a number of shell script parameters, as in the command shift 4.

3. using set --?

the set -- shift command is useful in setting default command line parameters if the user should omit them. in the set -- feature back quotes are commonly used to specifically set the parameter.

example: if [ $# = 0 ] # test if parameter count is 0. then set -- `who | grep charles` # sets and greps for charles in the login parameters for who is logged on. fi

echo $1 is logged in on $2

4. using IFS?

the command line parameters are separate by spaces and or tabs. we can use the IFS internal field separate variable to designate the character(s) that will be used to separate one command line parameter from the next.

example: if [ $# = 0 ] # test if parameter count is 0. then IFS=: set -- `who | grep charles /etc/passwd` # sets and greps for charles in the password parameters.

fi

echo home dir for $1 is $6

5. usage messages?

a usage message is a couple lines of text that are displayed if a user incorrectly specifies command line parameters. the usage message should go to standard error by adding 1>&2 to the end of the echo statement. 1 standard output gets sent to the same place as 2 error output.

$0 contains the name of the script as it was entered on the command line, this is used so you do not have to change the usage message. $0 cannot be shifted. basename $0 is used to trim the length the name of the script.

example: usage: grep [option] . . . pattern [filename . . . ] # the brackets specify parameters that are optional. example: if [ $# -lt 2 ] # test if parameter count is less than 2. then echo usage: myscript username file . . . exit 2 # exit status 2 is simply used to be unique from the 0 zero and 1 exit status.

fi

example: echo usage: $0 username filename 1>&2 # echo user name from the file and 1 standard output gets sent to the same place as 2 error output.

example: echo usage: `basename $0` username filename 1>&2 # trim the basename of the path for the user the remainder of the path is discarded in the errors file. 1 standard output gets sent to the same place as 2 error output.

6-7. exercises?

write a reusable function called usage that takes the script name as at least one parameter, echoes the script name and send the rest of the information to standard error, and beeps using the ctrl-g character, and exits the program with an exit status of 2. ensure that the base name echo usage: `basename $0` username filename 1>&2 is used on the script name.

usage() # function call for usage. { script=$1 shift # shift is done to separate out the basename from the other parameters so the first parameter can be # done first whilst leaving all the other parameters alone.

echo "^GUsage: `basename $script` $*" 1>&2 # the remainder of the path is discarded in the errors file. exit 2 # exit program with a return unique value of 2 to keep track of the program execution.

}

# # a test for the usage function # usage $0 filename username . . . # usages is set to filename.

modify the project so that it requires the name of the data file as a command line parameter. when the user specifies a file, check to see if it exists, if not exit the program. then if the file does not exist, ask the user if you can create it, and check to see if you successfully created it before proceeding.

# program 6

#!/bin/sh # # the above sh causes this script to be run using the bourne shell (sh). ####################################################### # # script to maintain database. # ####################################################### # # assign the filename. # fname=names.dat # code that assigns fname the value of the file names.dat is performed.

# # pause() # # ask the user to press and wait for them to do so. # pause() function call to pause. { # code to do pause is performed.

echo "hit to continue: \c" read junk }

# # yesno is a function to display a string passed in as $* any parameter, followed by "(y/n)?", # and asks for either a yes or no answer. nothing else is acceptable. # # if the answer is yes, yesno returns an exit status of 0 (true) # if the answer is no, yesno returns an exit status of 1 (false) # yesno() # function call to yesno. {

# code to do yesno is performed.

# # loop until a valid response is entered. # while : # : colon returns a value of zero 0 and means while true. do # # display the strings/parameters passed in, followed by "(y/n)?" # the \c causes suppression of echo's new line, and causes the cursor_ # to be place on the same line as the \c. # echo " $* (y/n?) \c" # $* means all the words that make up the y/n question.

# # read the answer - only the first word of the answer will # be stored in "yn". the rest will be discarded # courtesy of junk. # read junk

case $yn in y|Y|yes|Yes|YES) return 0;; # return true. n|N|no|No|NO) return 1;; # return false. *) # in a case where any answer other than yes or no is answered. echo please answer yes or no.;; # # and continue the loop. # esac done }

# # usage # generic function to display the usage message and exit the program. # the ^G is the bell character, "basename" is used to transform # the "/home/charles/contacts" into contacts. # usage() # function call to usage. {

# code to do usage is performed.

script=$1 shift # shift is done to separate out the basename from the other parameters so the first # parameter can be processed first whilst leaving all the other parameters alone.

echo "^GUsage: `basename $script` $*" 1>&2 # the remainder of the path is discarded in the errors file. exit 2 # exit program with a return unique value of 2.

}

# # do_create() # # create records for our database. # do_create() # function call to create.

{

# code to do create is performed.

# # loop until the user is sick of entering records. # while : do

# # inner loop. loop until the user is satisfied with this one record. # while : do

# # read the contact details from the keyboard. # clear # clear causes the screen to be cleared before the menu is displayed.

echo "please enter the following contact details:" echo echo "given name: \c" # note the placement of \c to create columns. read name echo " surname: \c" read surname echo " address: \c" read address echo " city: \c" read city echo " state: \c" read state echo " zip code: \c" read code # echo reads the details from the keyboard that are given to the read command.

# # now confirm. # clear

echo "you entered the following contact details:" echo echo "given name: $name" echo " surname: $surname" echo " address: $address" echo " city: $city" echo " state: $state" echo " zip: $zip" echo

if yesno are these details correct # yes exit value is 0 true and no exit value is 1 false. then

# # enter the details to the end of the file, # with the fields separated by colons, and # break out the inner loop # echo $name: $surname: $address: $city: $state: $zip: >> $fname # the data is echoed out onto the screen and appended to $fname and colons separate # the data information.

break # otherwise we go back through while the loop, if not we are done. fi done

# # ask the user if they wish to create a new record. # the "break" will only be executed if the user answers "no", then we are done. # yesno create another record || break # yes exit value is 0 true and no exit value is 1 false. done }

# # do_view() # # display all records in the file, complete with headings, # sorted one page at a time. # do_view() # function call to view.

{

# code to do view is performed.

clear

echo echo here are the current contacts in the database: echo echo "first name surname address city zipcode" echo "============================================" # # display the line correctly formatted. # use awk for the formatting. # the "-F :" causes awk to perceive fields to be separated by : colon. # "%14. 14s" displays a string in a string field width of 14 left justified. # sort -t : causes the shell to perceive fields to be separated by : colon and +1 # specifies the second field which is the surname field. # sort -t : +1 $fname | awk -F : '{printf("%-14. 14s%-16. 16s%-20. 20s%-15. 15s%-6. 6s%-5. 5s\n", $1, $2, $3, $4, $5, $6)}' # the formatting of the s strings is placed within the $ parameters. ) | more

# # display how many contacts there are. # echo echo there are `cat $fname | wc -l` contacts in the database. # back quotes allow echo to run the script output within the text that is echoed out onto # the screen where the number of files from the dat file are counted.

}

# # do_search() # do_search() # function call to search.

{ echo the search case is not implemented yet. }

# # do_delete() # do_delete() # function call to delete.

{ echo the delete case has not been implemented yet. }

# # start main menu #

# # check that there is exactly one argument. # "$#" contains the number of command line arguments. # "$0" is the complete path and the name of the shell script "/home/charles/menu." # [ $# == 1 ] || usage $0 filename # test whether the number count $# equals one or $0 the first parameter if not exit the menu program.

# # if we got here they must have provided a filename. # fname=$1 # store filename.

# # check if the filename is valid. # if [ ! -f $fname ] # if ! not a file in fname then echo some text. then echo $1 does not exist.

# # ask if the user if he would like to create the file. # if yesno "create it" then # # attempt to create it. # if the user says yes then create the file. # > $fname # output the input to fname.

# # check if that succeeded. # if [ ! -w $fname ] # test whether the file is writable. then echo $1 the file could not be created. exit 2 # if fname is ! not writable identify the unwritable file and exit program with a unique value of 2.

fi

# # otherwise we're ok. #

else # # they did not want to create the file. # exit 0 # if filename is writable exit program with a value of true 0.

fi

elif [ ! -w $fname ] # the program exits, and checks to see if the file can not be written to. then echo could not open $1 for writing. exit 2 # if fname is ! not writable exit program with a unique value of 2.

fi

# # loop forever, until the user wants to exit the program. # while true # if the exit value is true 0 do menu display.

do

# # display the menu. # clear # cause the screen to be cleared before the menu is displayed. echo "\n\t\tshell programming database." # \n newline \t tab echo "\t\t\tmain menu" echo "\nwhat do you wish to do?" echo "\t1. create records." echo "\t2. view records." echo "\t3. search for records." echo "\t4. delete records that match a pattern." echo

# # prompt for an answer. # echo "answer (or 'q' to quit)? \c" # enter q to quit running the program. read ans junk # function call reads the answer, to quit is selected hear anything else gets sent to junk

# # empty answers, pressing enter cause the menu to redisplay, # so we go back around the loop. # we only make it to the "continue" bit if the "test" # program "[" returned 0 true. # [ "$ans" = "" ] && continue # test empty answer to redisplay the menu selection.

# # decide what to do. # case $ans in 1) do_create;; # create is returned to create function call. 2) do_view;; # view is returned to view function call. 3) do_search;; # search is returned to search function call. 4) do_delete;; # delete is returned to delete function call. q|Q*) if yesno "do you really wish to exit" then exit fi ;;

*) echo "please enter a number between 1 and 4^G" # select a case. ;; esac

# # pause to give the user a chance to see what is on the screen. # pause done

1. advanced scripting - debugging?

when your script does operate properly you must debug the code. debugging can be done using the sh -x filename command, which is a bourne shell facility.

from the command line, and with your curser at the line of code you are examining, you type sh -x %.

2. setting default values for variables?

var1="default value" # sets var1 to "default value". use : ${var1:="default value"} to avoid running the default value as a program.

3. temp files?

in who > /tmp/who_results a problem would occur. the problem is that many people would be running the same script and as a result the same tmp file would be used for all of them.

to guarantee that a filename is unique in the instance of this script append the $$ dollar, dollar variable to the end of the filename,

example: filename=/tmp/who_results.$$

the $$ dollar, dollar variable contains the process id of the current shell running the script, which means that a new process is created for each user who runs the script.

4. preventing abnormal termination?

in order to handle a signal, a script should begin with a trap command.

example: trap specifiedcommand signal . . .

1 SIGHUP occurs when the user's terminal is disconnected or the login is terminated. 2 SIGINT occurs when the user presses the interrupt key ctrl-c on the keyboard. 3 SIGQUIT occurs when the user presses the quit key ctrl-\ on the keyboard. 15 SIGTERM occurs when unix is in the process of shutting down, or if the process is manually killed. SIGUSR1 SIGUSR2 and on linux SIGUSR10 SIGUSR12 are available to developers for custom processing their programs.

trap ls 1 2 will cause the ls program to run whenever signals 1 and 2 are received. the specified command can be the name of a function, and parameters can be specified.

example: graceful_exit() { echo "exiting please wait." # clean up temp files. exit $1 } trap "graceful_exit 2" 1 2 15 # trap will cause the graceful_exit 2 program to run # whenever signals 1, 2 and 15 are received.

5-7 exercises?

use kill -l, kill list to determine which signal SIGUSR1 is, and create a script that does nothing at all but sleep until SIGUSR1 kills it. at which point it displays the current time and date, and a calendar of the current month, and continues to do nothing.

process_sig() { echo # a blank line for neatness. date # displays the current time and date, and a calendar of the current month, and # continues to do nothing. cal } trap process_sig 10

while: do sleep1 # a script that does nothing at all but sleep until SIGUSR1 kills it. done

complete the project by implementing the search and delete options. the search option should ask the user for a pattern to search for, and display all records that contain that pattern. the delete option should ask the user for a pattern to search for, and display all records that contain that pattern, and ask the user if they want to delete all those records.

a temporary file will be necessary for the delete option. if either SIGHUP (1) or SIGTERM (15) is received exit immediately.

if either SIGINT (2) or SIGQUIT (3) is received ask the user does he really want to quit now?

avoid using repeated code by turning that code into a separate function.

# program 7

#!/bin/sh # # the above sh causes this script to be run using the bourne shell (sh). ####################################################### # # script to maintain database. # ####################################################### # # assign the filename. # fname=names.dat # code that assigns fname the value of the file names.dat is performed.

# # set a name for all temp files used during this script. # the `basename $0` causes the filename to include the filename of this script. # $$ bit causes the filename to include a number unique to this shell, # in case more than one copy of this script is running at any one time. #

# code that assigns the path to a unique temporary file and trims the path for the # users name is performed.

tmpfile=/tmp/`basename $0`.$$

# # pause() # # ask the user to press and wait for them to do so. # pause() # function call to pause. {

# code to do pause is performed.

echo "hit to continue: \c" read junk }

# # yesno is a function to display a string passed in as $* any, followed by "(y/n)?", # and ask for either a yes or no answer. nothing else is acceptable. # # if the answer is yes, yesno returns an exit status of 0 (true) # if the answer is no, yesno returns an exit status of 1 (false) # yesno() # function call to yesno. {

# code to do yesno is performed.

# # loop until a valid response is entered. # while : # : colon returns a value of zero 0 and means while true. do # # display the strings/parameters passed in, followed by "(y/n)?" # the \c causes suppression of echo's new line and causes the cursor_ # to be place on the same line as the \c. # echo " $* (y/n?) \c" # $* means all the words that make up the y/n question.

# # read the answer - only the first word of the answer will # be stored in "yn". the rest will be discarded # courtesy of junk. # read junk

case $yn in y|Y|yes|Yes|YES) return 0;; # return true. n|N|no|No|NO) return 1;; # return false. *) # in a case where any answer other than yes or no is answered. echo please answer yes or no.;; # # and continue the loop. # esac done }

# # usage # generic function to display the usage message and exit the program. # the ^G is the bell character, "basename" is used to transform # the "/home/charles/contacts" into contacts. # usage() # function call to usage.

{

# code to do usage is performed.

script=$1 shift # shift is done to separate out the basename from the other parameters so the first # parameter can be done first whilst leaving all the other parameters alone.

echo "^GUsage: `basename $script` $*" 1>&2 # the remainder of the path is discarded in the errors file.

exit 2 # exit program with a unique value of 2.

}

# # quit() # prompts the user to exit the program. # if the user chooses to exit the program, an exit code is provided in $1, # the first argument. # quit() # function call to quit.

{

# code to do quit is performed.

# # store the exit code away, calling another function overwrites the $1. # code=$1 # if the user says yes, quits using the single parameter to the quit function. if yesno "do you really want to exit?" then exit $code # exit using the supplied code. fi

}

# code to do headings is performed.

# # heading() # display the standard heading when displaying the records. # heading() # function call to heading.

{ echo "first name surname address city state zipcode" echo "====================================================" }

# # print_records() # reads records from standard input and nicely formats each on one line. # this function would typically use a pipe e.g. grep pattern file | print_records(). # if this format changes do not forget to change the heading function. # print_records() # function call to do print records.

{

# code for formatting and printing records is performed.

# # read from the standard input and loop once for each line of input. # sort -t : +1 | while read aline do

# # display the formatting, use awk to format. # the -F cause awk to perceive the fields as being separated by colon :. # "%-14,14s" displays the string in a field width of 14, and left justified. # echo $aline | awk -F : '{printf("%-14.14s%-16.16s%-20.20%s-15.15s%-6.6s%-5.5s\n", $1, $2, $3, $4, $5, $6)}' # the formatting of the s strings is placed within the $ parameters. }

# # do_create() # # create records for our database. # do_create() # function call to do create.

{

# code to create record is performed.

# # loop until the user is sick of entering records. # while : do

# # inner loop. loop until the user is satisfied with this one record. # while : do

# # read the contact details from the keyboard. # clear # clear causes the screen to be cleared before the menu is displayed.

echo "please enter the following contact details:" echo echo "given name: \c" # note the placement of \c to create columns. read name echo " surname: \c" read surname echo " address: \c" read address echo " city: \c" read city echo " state: \c" read state echo " zip code: \c" read code # echo reads the details from the keyboard that are given to the read command.

# # now confirm. # clear

echo "you entered the following contact details:" echo echo "given name: $name" echo " surname: $surname" echo " address: $address" echo " city: $city" echo " state: $state" echo " zip: $zip" echo

if yesno are these details correct # yes exit value is 0 true and no exit value is 1 false. then

# # enter the details to the end of the file, # with the fields separated by colons, and # break out the inner loop # echo $name: $surname: $address: $city: $state: $zip: >> $fname # the data is echoed out onto the screen and appended to $fname and colons separate # the data information.

break # otherwise we go back through while the loop, if not we are done. fi done

# # ask the user if they wish to create a new record. # the "break" will only be executed if the user answers "no", then we are done. # yesno create another record || break # yes exit value is 0 true and no exit value is 1 false. done }

# # do_view() # # display all records in the file, complete with headings, # sorted one page at a time. # do_view() function call to do view.

{

# code to do view is performed.

clear

# # show what is currently in the file. # ( heading

# # display the lines correctly formatted using the print_records function. # cat $fname | print_records ) | more

# # display how many contacts there are. # echo echo there are `cat $fname | wc -l` contacts in the database. # back quotes allow echo to run the script output within the text that is echoed out onto # the screen where the number of files from the dat file are counted.

}

# # do_search() # prompt the user for the pattern to search for, display all # results nicely formatted, with headings. # it is possible to display all records by entering an empty string. # if any records are found, do_search() return with an exit status of true 0. # if no records are found, do_search return with an exit status of 1 false. # do_search() # function call to do search is performed.

{

# code for search is performed.

echo "please enter the enter the pattern to search for (press the enter key for all): \c" read string echo

# # check to see if there are any records in the file that match the pattern. # if there are, "grep" will return true 0, which is used in the "if" statement. # we do not want to see the results yet so send the results to trash "/dev/null" # if grep "$string" $fname >/dev/null # search simply searches for the requested data string in fname, and avoids printing # out or manipulating the data by sending output to /dev/null.

then # # use the parenthesis to group the heading and records together. # ( heading

#
# search the file again and this time send the output to "print_record"
# for formatting using the sort.
#
grep "$string" $fname | print_records # if the $string matches the search for data
# contained in the parameters of $fname then it is piped to be formatted by print_records.
) | more
return 0 # returns true if we found some records
else

echo "sorry, no records in file \"fname\" that contain \"$string\" "
return 1 # returns false if we did not find any records.
fi
}

#
# do_delete()
# use the prompt to find all records matching a certain pattern.
# prompt the user for confirmation to delete those records.
# it is possible to delete all records by entering an empty search string.
#

do_delete() # function call to delete.
{

# code to do delete is performed.

#
# search for records matching a certain pattern. if any records are found,
# do_search will return true 0. then we go to the yesno bit which will ask us
# if we want to delete the records. if we answer no we will be forced to
# move on to the return bit which will exit this function. otherwise we
# delete the records.
#
# the effect of calling the "do_search" function is that the "$variable" gets set.
#
do_search && yesno "\ndelete all these records" || return

#
# now delete the records
# if the $string is empty delete all the records.
#
if [ "$string" = "" ]
# if the string is empty, an empty string is input to fname.

then

# # simply clear the file.
#
> $fname # performs a file create or either sends data input to fname.

echo "all the records have been deleted from file \"$fname\" "
else

#
# delete the records using "sed". sed does not change the file, so
# we use a temp intermediate file.
#
sed "/$string/d" $fname >> $tmpfile
# d deletes the string of data in fname and appends an empty parameter to the temporary
# file and mv moves the empty parameter back to fname.
mv $tmpfile $fname

echo "all records containing the text \"$string\" were deleted from file \"$fname\"
fi
}

#
# start main menu
#

# code to start menu is performed.

#
# for the duration of the program ensure that signals 2 and 3, ctrl-c and ctrl-\
# cause the program to quit using the "quit" function rather than dying.
#
# we pass the "quit" an argument of 3 so that if the user uses ctrl-c
# we return an exit code of 3 to the parent shell.
#
# 15 SIGTERM is the result of the system shutting down.
# 1 SIGHUP is the result of a broken connection or terminated login shell, as in telnet.
# no confirmation is required just to exit.
#
trap "quit 3" 2 3 # signals 2 and 3, ctrl-c and ctrl-\ cause the program to
# quit using the "quit" function.
trap "exit 0" 1 15 # 15 SIGTERM is the result of the system shutting down.
# 1 SIGHUP is the result of a broken connection or terminated
# login shell.

#
# check that there is exactly one argument.
# "$#" contains the number of command line arguments.
# "$0" is the complete path and the name of the shell script "/home/charles/menu."
#
[ $# == 1 ] || usage $0 filename # exits the program.

#
# if we got here the user must have provided a filename.
#
fname=$1 # store filename in $1 parameter one.

#
# check if the filename is valid.
#
if [ ! -f $fname ] # if ! not a file in fname then echo some text.
then
echo $1 does not exist.

#
# ask if the user if he would like to create the file.
#
if yesno "create it" # yes exit value is 0 true and no exit value is 1 false.
then
#
# attempt to create it. # if the user says yes then create the file.
#
> $fname # performs a file create or either sends data input to fname.

#
# check if that succeeded.
#
if [ ! -w $fname ] # performs check whether $fname is ! not -w writable.
then
echo $1 the file could not be created.
exit 2
# if fname is ! not writable exit program with a unique value of 2.

fi

#
# otherwise we're ok.
#

else
#
# they did not want to create the file.
#
exit 0
# if filename is writable exit program with a value of true 0.

fi

elif [ ! -w $fname ] # the program exits, and checks to see if the file can not be written to.
then
echo could not open $1 for writing.
exit 2
# if fname is ! not writable exit program with a unique value of 2.

fi

#
# loop forever, until the user wants to exit the program.
#
while true
# if the exit value is true 0 do menu display.

do

#
# display the menu.
#
clear # cause the screen to be cleared before the menu is displayed.
echo "\n\t\tshell programming database." # \n newline \t tab
echo "\t\t\tmain menu"
echo "\nwhat do you wish to do?"
echo "\t1. create records."
echo "\t2. view records."
echo "\t3. search for records."
echo "\t4. delete records that match a pattern."
echo

#
# prompt for an answer.
#
echo "answer (or 'q' to quit)? \c" # enter q to quit running the program.
read ans junk
# function call reads the answer, to quit is selected hear anything else gets sent to junk

#
# empty answers, pressing enter cause the menu to redisplay,
# so we go back around the loop.
# we only make it to the "continue" bit if the "test"
# program "[" returned 0 true.
#
[ "$ans" = "" ] && continue # test empty answer to redisplay the menu selection.

#
# decide what to do.
#
case $ans in
1) do_create;; # create is returned to create function call.
2) do_view;; # view is returned to view function call.
3) do_search;; # search is returned to search function call.
4) do_delete;; # delete is returned to delete function call.
q|Q*) quit 0;;

*) echo "please enter a number between 1 and 4^G" # demand the user select a case.
esac

#
# pause to give the user a chance to see what is on the screen.
#
pause # pause is returned to pause function call.
done

# the end