Simple Date & Time Functions Simple File Setup Functions Simple String Functions Simple Menu Functions Simple Utility Functions SQL*Net 1.0 Functions

Functions

The Function or Subroutine is one of the most useful features of the shell programming languages. The man pages generally call them Functions which is what I have done here but this can lead to misunderstandings. By definition a function must return one thing but sometimes these shell functions return more than one by using stdout as well as the return value. The things you need to remember are best listed out as short reminders which can then be used as a quick reference guide later. This then, is my list of useful things to know about shell subroutines or functions.
  1. A function encapsulates a small piece of code that will be used often.
  2. You only need to define it once.
  3. A function will execute faster than the equivalent code in the script.
  4. Parameters are passed into the function via numbered arguments just like scripts.
  5. The special shell variables are also set up when a function is called ($#, $@, etc.) but in this case they relate to the called function not the calling script. Their scope is local to the function.
  6. Output can be in the form of stdout or a return code value or both. You cannot stop the function returning a value via its return code, but you can exercise control over the return code. If you choose not to, then the function will return the value of the last executed sub command from within the function.
  7. Variables used and set inside a function can be visible from the calling script and
  8. Variables set within the environment or calling script can be visible in the function. This relies on the use of the export command in both directions.
  9. Functions can be nested to any depth - well I haven't found a limit.
  10. No amount of nesting will ever disguise the $0 parameter. The $0 will never be set to the function name, it is only ever set to the name of the calling script.
  11. With care and shift, any number of parameters can be handled.

If you think of any more, please add them to this list yourself. The rest of this section contains example listings of some of my own functions, which I have created over the years to support my normal script programming activities. They are grouped into areas (strings, files, menus, etc.) and stored in separate files. A master profile exists for the accounts which execute the scripts and this profile adds in all the function files at run time. If this sounds slow and complicated, it isn't. In practice, the separate files are easier to handle, edit and distribute around a networked system. The additional start-up time for scripts which have to read 200 functions is less than 0.5 seconds. This is more than compensated for by the shorter scripts which result, the easier maintenance load, the faster script creation time, etc. Well, that's enough of that, lets get on with some examples. Note the use of the function name itself as part of the banner line for each function. The (c) flag is there for another script called fun which searches out lines containing the flag in all the function definition files. In this way it is easy to get an up-to-date list of all the functions currently available.

Simple Date and Time functions:


#===================================================================
s_timestamp()	# (c) RHReepe. Returns string (YYYY-Mon-DD@HH:MM:SS)
#===================================================================
{
    date "+%Y-%h-%d@%H:%M:%S"
}
#===================================================================
s_now()	# (c) RHReepe. Returns string (YYYYMMDDHHMMSS)
#===================================================================
{
    date +%Y%m%d%H%M%S
}
#===================================================================
s_time()	# (c) RHReepe. Returns string (HHMMSS)
#===================================================================
{
    date +%H%M%S
}
====================================================================
s_date()	# (c) RHReepe. Returns string (YYYYMMDD)
#===================================================================
{
    date +%Y%m%d
}

They may look simple, but in each case the character count of the function name is about half that of the function content. That in itself is enough justification. It also means you never need to remember the combination of letters (and cases) required to generate your date or time string ever again. You might also notice the use of capital "Y" in all the date oriented functions. If you check out the man pages for the date command, you probably won't find any references to "Y" at all. That's because the plus sign (+) actually tells date to call another function called strftime which understands a lot more formatting arguments than date does. Check out the man pages for strftime for yourself.

 
#=====================================================================
s_month_length()	# (c) RHReepe. Returns number of days in MONTH (INT)
#=====================================================================
# Arg_1 = MONTH_NUMBER
{
    if [ $1 -lt 1 ] || [ $1 -gt 12 ]
    then
	echo "$0:s_month_length(): [$1] \
	     is not between 1 and 12"
	exit
    fi
    lengths="312831303130313130313031"
    cut2=`expr $1 + $1`
    cut1=`expr $cut2 - 1`
    echo $length | cut -c$cut1-$cut2
}

The s_month_length() function is quite simple but watch out for leap years as there is no account taken of Feb 29th. The fix is actually quite easy too - just divide the year by 4, then multiply by 4, and see if you get the same number you started with. You will need to use the bc command for division and multiplication. If it is the same number then Feb may have 29 days (unless its a century, or maybe it still does, if it's a millenium!).

Now here are two slightly more complex examples, s_interval() and s_back_date(), which get used for checking out superceded archives and timing test functions or scripts. The function s_interval() is fully in-stream documented. This is a bit over the top in this example, but you should be able to see how such treatment enhances understanding when reading the functions. In fact the only additional thing I'll say about this function, is that I use it to time new scripts and functions to help me tune out any slow operations. It has two mandatory arguments which can be provided by calling the s_time() function at each end of the timed process. The output is in the same format (HHMMSS), don't forget and think that 000120 = 2 minutes, it is 1 minute 20 seconds.



#===================================================================
s_interval()	# (c) RHReepe. Returns a time difference (HH:MM:SS)
#===================================================================
# Arg_1 = start_time (Format - See s_time)
# Arg_2 = stop_time  (Format - See s_time)
{
    h1=`echo $1 | cut -c1-2`	# Get Start Hour
    m1=`echo $1 | cut -c3-4`	# Get Start Minute
    s1=`echo $1 | cut -c5-6`	# Get Start Second
    h2=`echo $2 | cut -c1-2`	# Get Stop Hour
    m2=`echo $2 | cut -c3-4`	# Get Stop Minute
    s2=`echo $2 | cut -c5-6`	# Get Stop Second
    s3=`expr $s2 - $s1`		# Calculate Second Difference
    if [ $s3 -lt 0 ]		# Test for Negative Seconds
    then
	s3=`expr $s3 + 60`	# If yes - add one minute...
	m1=`expr $m1 + 1`		# ... and to subtractor
    fi
    m3=`expr $m2 - $m1`		# Calculate Minute Difference
    if [ $m3 -lt 0 ]		# Test for Negative Minutes
    then
	m3=`expr $m3 + 60`	# If yes - add one hour...
	h1=`expr $h1 + 1`		# ... and to subtractor
    fi
    h3=`expr $h2 - $h1`		# Calculate Hour Difference
    if [ $h3 -lt 0 ]		# Test for Negative Hours
    then
	h3=`expr $h3 + 24`	# If yes - add one day
    fi
    for number in $h3 $m3 $s3	# Loop through numbers...
    do
	if [ $number -lt 10 ]	# If number is single digit...
	then
	    /usr/5bin/echo "0$number\c" # ... add leading zero
	else
	    /usr/5bin/echo "$number\c"  # ... else - don't
	fi
    done
    echo ""			# Terminate the string
}

Lastly the function s_back_date() which returns a date, an integer number of days before today. This is used to check when to retire an old archive for instance. Internal documentation has been limited to block headers this time to highlight the differences is presentation. Note the use of the optional parameter [DAYS:-1] with a default of one-day, so calling the function with no arguments will return you yesterdays date. The date string padding in the final block shows an example of un-typed data concatenation, as the predicate tests the numeric value of the strings, then prepends a string zero if it is too short. There is no attempt to cope with back dates that flow over a year boundary. This could be added for completeness if required by replicating the outer if-else-fi structure under the date_m decrement statement.


#=====================================================================
s_back_date	# (c) RHReepe. Returns a date string DAYS back
#=====================================================================
# Arg_1 = [DAYS:-1]
{
    days=${1:-1}
    date_d=`date +%d`
    date_m=`date +%m`
    date_y=`date +%Y`
	#--------------------------------
	# Days Back Size Test
	#--------------------------------
	if [ $days -lt $date_d ]
	then
		date_d=`expr $date_d - $days`
	else
		days=`expr $days - $date_d`
		date_m=`expr $date_m - 1`
		month_length=`s_month_length $date_m`
		while [ $days -gt $month_length ]
		do
			days=`expr $days - month_length`
			date_m=`expr $date_m - 1`
			month_length=`s_month_length $date_m`
		done
		date_d=`expr $month_length - $days`
	fi
	#--------------------------------
	# Date	String Padding
	#--------------------------------
	if [ $date_d -lt 10 ]
	then
		date_d="0"$date_d
	fi
	if [ $date_m -lt 10 ]
	then
		date_m="0"$date_m
	fi
	echo $date_y $date_m $date_d
}

Simple File Set-up Functions:

This next section deals with functions related to file set-up. This includes temporary files, status flags, log-files and many other related functions. Some of these may seem simple and rudimentary, but that is less important than easing the readability of the calling scripts and reducing the need to re-code the same thing several times.


#===================================================================
s_prog()	# (c) RHReepe. Returns the calling script name
#===================================================================
{
	basename $0
}
#===================================================================
s_file()	# (c) RHReepe. Creates a file name
#===================================================================
# Arg_1 = file extension
# Arg_2 = unique identifier
{
	temp_file="/tmp/db_`s_prog`_$$_$2.$1"
	rm -f $temp_file
	touch $temp_file
	echo $temp_file
}
#===================================================================
s_rmfile()	# (c) RHReepe. Removes file names
#===================================================================
# Arg_1 = [file extension]
# Arg_2 = [unique ientifier]
{
	rm -f /tmp/db_`s_prog`_$$_${2:-""}*.${1:-""}*
}
#===================================================================
s_tmp()		# (c) RHReepe. Creates a TMP filename
#===================================================================
# Arg_1 [unique identifier]
{
	s_file tmp ${1:-$$}
}
#===================================================================
s_rmtmp()	# (c) RHReepe. Removes a TMP filename
#===================================================================
# Arg_1 = [unique identifier]
{
	s_rmfile tmp ${1:-$$}
}
#===================================================================
s_sql()		# (c) RHReepe. Creates a SQL filename
#===================================================================
# Arg_1 [unique identifier]
{
	s_file sql ${1:-$$}
}
#===================================================================
s_rmsql()	# (c) RHReepe. Removes a SQL filename
#===================================================================
# Arg_1 = [unique identifier]
{
	s_rmfile sql ${1:-$$}
}
#===================================================================
s_log()		# (c) RHReepe. Creates a LOG filename
#===================================================================
# Arg_1 [unique identifier]
{
	s_file log ${1:-$$}
}
#===================================================================
s_rmlog()	# (c) RHReepe. Removes a LOG filename
#===================================================================
# Arg_1 = [unique identifier]
{
	s_rmfile log ${1:-$$}
}
#===================================================================
s_cleanup()	# (c) RHReepe. Cleans up ALL files for this script
#===================================================================
# Arg_1 = [unique identifier]
{
	s_rmfile ??? ${1:-""}
}
#===================================================================
s_truncate()	# (c) RHReepe. Truncates extension from a filename
#===================================================================
# Arg_1 - FILENAME
{
	dot=`s_in_string $1 "."`
	dot=`expr $dot - 1`
	echo $1 | cut -c1-$dot
}
#===================================================================
s_running()	# (c) RHReepe. Checks if script is running
#===================================================================
{
	if [ -f /tmp/db_`s_prog`_running.lock ]
	then
		echo "Script [$0] is already running!"
		exit -1
	else
		touch /tmp/db_`s_prog`_running.lock
	fi
}
#===================================================================
s_stopping()	# (c) RHReepe. Removes running lock file
#===================================================================
{
	rm -f /tmp/db_`s_prog`_running.lock
}

There are probably some surprises here, so I'll try and explain them starting with s_prog(). You may wonder why I have used basename in this function when the name of the calling script is blatantly obvious. Well just try and run a script from the crontab and display the script name with echo $0 in the script and see what happens. If you can't wait that long, I'll tell you. What you get is the scripts full pathname (/co/host/u/user_accounts/me/scripts/better_scripts/really_brill_stuff/yo_man) which is really going to look professional when it finds its way into a logfile! Note also that each of the subsequent functions makes a call to s_prog() internally, another bunch of characters you won't have to type in.

The next two functions I class as paired (s_file(), s_rmfile()) as one creates something and the other removes it. In this case we are talking about general files, the function s_file() pre-deletes the file in case one already exists, then creates an empty file using touch, then last of all the filename is returned via stdout which can be used to set a variable. The function has two arguments which are both mandatory. The first is the extension to use at the end of the filename, and second is a unique identifier, required if you want to create more than one file of this type from within the same script. The next function s_rmfile() removes the files created by the first function, as long as you provide the optional arguments - extension and unique identifier. If you forget to provide the arguments, it will remove all the files created during the running of the calling script. This may sound a bit dangerous, but this is where the nesting of functions starts to show real benefits.

Take a look at the next six functions s_tmp(), s_rmtmp(), s_sql(), s_rmsql(), s_log() and s_rmlog() all of which make calls on s_file() and s_rmfile(). The three create functions all have an optional single argument - unique identifier - which allows you to have some control over the actual filename. If you choose not to exercise this right, then the function will select the PID of the parent script and use that instead. Note that all of these create functions call the s_file() function with a fixed extension based on their own names. The same is true of the three remove functions also, which makes it particularly easy to use these higher level functions within a script. Notice also that the function s_cleanup() is nothing more than a call to s_rmfile() with one argument. Inspecting the function s_rmfile() will reveal what is happening. Its optional argument is set to NULL or the empty string ("") when no argument is supplied. Hence the expanded filename includes all members of the group /tmp/db_[calling_script_name]_[PID]_*.??? and so cleans up all files created by this run of the script. By copying the two tmp functions several times and revising the three character extensions for the filenames, you can create functions to manage .log , .sql , .tmp , .dat , .bin, .lst, etc.

Following on is the function s_truncate() which is used to remove the extension from some filenames. The function makes no changes to the file itself, you will still have to move or copy the file yourself if you want it done. The function just returns the name minus its extension. It works by searching for the dot in the name and returning what is in front of the dot. A word of warning, beware filenames with more than one dot, this function will cut at the first dot found. If you really wanted to check for three character extensions only and allow multiple dots in the filenames, get the length of the name and set up the cut to always remove 4 characters from the end, but this will lock you in to three character extensions only. You may spot a more elegant way to achive this after studying the next group of string functions.

The next two functions are again paired but these two relate to script instance control. When running some scripts, it is important to know that there is only one instance (it is only running once on the CPU). The s_running() function checks for a running flag file and if not found creates one, thus setting the flag. If there is an existing flag file, then the function exits. Usefully, the exit statement also terminates its calling script as well as the processing function, aborting the script if an instance is already running. The s_stopping() function is provided to clean up the flag file just as the script terminates. These two functions are placed at the head and tail of a script to protect against multiple instances.

Simple String Functions:

This next batch all relate to string functions and text handling. Starting simply with join strings and case changers, we move on through padding into character and string searches.


#===================================================================
s_join()	# (c)RHReepe. Creates single string from several
#===================================================================
# Arg_n = Input Strings
{
	echo "$@" | tr ' ' '_'
}
#===================================================================
s_upper()	# (c) RHReepe. Returns input string in upper case
#===================================================================
{
	echo $@ | tr '[a-z]' '[A-Z]'
}
#===================================================================
s_lower()	# (c) RHReepe. Returns input string in lower case
#===================================================================
{
	echo $@ | tr '[A-Z]' '[a-z]'
}
#===================================================================
s_count_args()	# (c)RHReepe. Returns count of input ARG_LIST
#===================================================================
# Arg_n = ARG_LIST
{
	echo $#
}
#===================================================================
s_count_lines()	# (c)RHReepe. Returns count of lines in FILENAME
#===================================================================
# Arg_1 = FILENAME
{
	line_count=`wc -l $1 | cut -c1-8`
	expr $line_count + 0
}
#===================================================================
s_length()	# (c)RHReepe. Returns length of string
#===================================================================
# Arg_1 = string
{
	length=`echo "$@" | wc -c | cut -c1-8`
	length=`expr $length -1`
}
#===================================================================
s_right_pad()	# (c)RHReepe. Right pads a string to width
#===================================================================
# Arg_1 = string
# Arg_2 = width
{
	string="$1                                         "
	echo "$string" | cut -c1-$2
}
#===================================================================
s_left_pad()	# (c) RHReepe. Left pads a string to width
#===================================================================
# Arg_1 = string
# Arg_2 = width
{
	string="                                         $1"
	length=`s_length "$string"`
	echo "$string" | cut -c`expr $length - $2`-$length
}
#===================================================================
s_find_char_all() # (c) RHReepe. Finds all positions of CHAR in LIST
#===================================================================
# Arg_1 = CHAR
# Arg_n = LIST
{
	echo "$@" | cut -f2- -d\ | sed -e 's/./&\
	/g' | grep -n $1 | cut -f1 -d:
}
#===================================================================
s_find_char() # (c) RHReepe. Finds first position of CHAR in LIST
#===================================================================
# Arg_1 = CHAR
# Arg_n = LIST
{
		s_find_word_all "$@" | head -1
}
#===================================================================
s_get_char()	# (c) RHReepe. Returns the CHAR at POSITION in LIST
#===================================================================
# Arg_1 = POSITION
# Arg_n = LIST
{
	echo "$@" | cut -f2- -d\ | cut -c$1 -d\
}
#===================================================================
s_find_word_all() # (c) RHReepe. Finds all positions of word in list
#===================================================================
# Arg_1 = word
# Arg_n = list
{
	echo $@ | cut -f2- -d\ | tr ' ' '\n' \
		| grep -n $1 | cut -f1 -d:

#===================================================================
s_find_word() # (c) RHReepe. Finds first position of word in list
#===================================================================
# Arg_1 = word
# Arg_n = list
{
	s_find_word_all $@ | head -1
}
#===================================================================
s_get_word()	# (c) RHReepe. Returns the word at position in list
#===================================================================
# Arg_1 = position
# Arg_n = list
{
	echo $@ | cut -f2- -d\ | cut -f$1 -d\
}

This is an interesting little collection. Starting from the top, the s_join() I created as a specific bug fix for a piece of mail software. I needed a way of picking up a list of words (used as the mail title) and making one long string. I tried various forms of quoting to encapsulate the string, but the mail software always took the first word as the title and tried to mail to all the other words as addressees. The function has since found other uses and is a good example of the tr command which is used to translate characters piped through it from the first quoted string to the second.

Next come two related functions which should be very obvious from their names alone. They simply change the case of the passed string. Note the use of $@ which passes all the arguments as one list.

Next is another very simple function s_count_args() which finds use in lots of places. Again this makes use of a very simple feature of the shell, the $# parameter, which returns the number of passed arguments. So passing a list of words to the function causes it to return the integer number of words.

The s_length() function returns the character length of a string. Again $@ is used to get all the parameters in a single pass. Here the character count is reduced by one as the wc -c command will include the newline (\n) at the end of the echo by default.

The next two functions are interesting for their unusual approach to a problem. Give any normal programmer a specification for a left pad or right pad function and they will start creating loops that add a character at each pass. In the shell, we can make use of the cut command and simple un-typed concatenation of dissimilar variables (the input string could be a number) to create first a long string, and then chop off the wanted length to give a quick result. There is one extra command in the left pad as we need to find where the end is before we can make the right hand cut.

The last six functions in this section are split into two groups. The first deals with searching for characters in strings. The second deals with searching for words in strings. The function s_find_char_all() is the base function in the first group. It makes use of the sed command in a novel way. The sed command is a Stream EDitor which has been passed a quoted command string. The command substitutes every character in the input stream to the same character plus a newline. This turns our horizontal input string into a vertical list of characters placed one per line. Now it's easy, the next command is a grep to find the character in $1, the -n option requests grep to give the line number as well as the found string. Then along comes cut and snips out the line number to be returned.

Of course this will return a list of line numbers if there is more than one match. If you only want to find the first match, then use the s_find_char() function which includes the head -1 statement. In the previous group I said a more elegant solution may present itself, and here it is. Just replace the head -1 with tail -1 and you have the location in the string of the last dot instead of the first. This can then be used to trim the filename extension correctly, however long it is.

Lastly, the s_get_char() function returns the character found at position in the string. Nothing very difficult here, but just remember to put the double quotes around the $@ symbol or the character counts will be out if some characters are separated by multiple blanks.

The second group of functions consists of s_find_word_all(), s_find_word() and s_get-word(). The first function s_find_word_all() actually contains 5 piped commands. Lets lay them out individually:

echo $@Echo ALL Arguments
cut -f2-Forget the first Argument
tr ' ' '\n'Translate the SPACES to NEWLINES
grep -n $1Get the LINE NUMBER where WORD appears
cut -f1 -d:Cut off the LINE NUMBER and return it

You will notice the similarity to the previous group of functions, except sed is not required here. This function also delivers a list of matches if there is more than one. The next function just calls the first one and adds the head -1 statement as before, thus returning only the first match. The last s_get_word() function is just as simple. Notice that the final cut statement only has one address for the cut ( cut -f$1 ). As both addresses are the same when one item (f = field, c = char) is cut, the second address is optional. Look for these short cuts and optional syntax forms, the reduction in code size can stack up nicely in larger modules.

Simple Menu Functions:

This next section contains functions related to Menu operations. This was one of the first groups that I created when one of my collegues requested an easier interface than remembering the command line arguments. Certainly for the rarely used scripts and even for the regular scripts which require the user to select from a list, these are worthwhile functions.


#===================================================================
s_banner()	# (c) RHReepe. Creates a banner for User Menus
#===================================================================
# Arg_n = BANNER_TEXT
{
	clear
	echo ""
	echo "	__________________________________________"
	echo ""
	echo "	 $@"
	echo "	__________________________________________"
	echo ""
}
#===================================================================
s_menu_list()	# (c) RHReepe. Creates a Menu List from a Directory
#===================================================================
# Arg_1 = DIRECTORY
{
	count=0
	for file in $1/*
	do
		count=`expr $count + 1`
		echo "	$count	`basename $file`"
	done
}
#===================================================================
s_answer()	# (c) RHReepe. Returns a Menu Pick Pointer Number
#===================================================================
# Arg_1 = PROMPT_STRING
# ARG_2 = [MAX_MENU_PICKS:-NULL]
{
	answer=""
	max=${2:-""}
	while [ "$answer" -lt "1" ] || [ "$answer" -gt "$max" ]
	do
		echo ""
		/usr/5bin/echo "	$1 ( Between 1 and $max ) : \c"
		read answer
		if [ "$answer" = "" ]
		then
			exit
		fi
	done
	return $answer
}
#===================================================================
s_menu_pick()	# (c) RHReepe. Returns the Filename from the Menu
#===================================================================
# Arg_1 = DIRECTORY
# Arg_2 = MENU_POINTER
{
	count=0
	for file in $1/*
	do
		count=`expr $count + 1`
		if [ $count = $2 ]
		then
			echo "$file"
		fi
	done
}

The first function s_banner() is very easy, it just takes a list of words as input and places a nice line above and below all one tab space in. The clear makes sure you have a nice empty screen for your menu.

Next is the function s_menu_list() which generates a nice numbered list under the heading. Be careful if the list extends off the screen as it will just scroll away. It also takes longer to generate the list if it gets too long. Use more subdirectories and fewer files per directory to speed up usage.

Next up is the function s_answer() which prompts the user to select from the list just generated. The users answer must be between 1 and max where max is the number of the last entry in the list. A special case is made for a null string (carriage return on a blank line) which is used as the exit from the menu and also terminates the script, in case or user error.

Lastly, we have the function s_menu_pick() which returns the filename the user selected from the menu as a text string. The filename includes the complete path as well, so don't add that back on.

By using these four functions together, a very succinct menu system can be generated out of the file system. With careful planning this can be a real boon when organising files or selecting backups and archives to retore etc. I have not yet crated a function to generate a menu from a list in a file, but it can only be a matter of time!

Simple Utility Functions

This next group do not fit in any other category, so I have lumped them all together for now. You have met two already from this group, but these are the final versions.


#===================================================================
s_version()	# (c) RHReepe. Returns 1 (cron) or 0 (not cron)
#===================================================================
# Arg_1 = [SCRIPT_NAME]
{
	head -3 ${1:-$0} | grep "(c)" | grep Version | cut -f9 -d\ 
}
#===================================================================
s_is_cron()	# (c) RHReepe. Returns 1 (cron) or 0 (not cron)
#===================================================================
{
	tty | grep -ci not
}
#===================================================================
s_syntax()	# (c) RHReepe. Checks Script Syntax Usage
#===================================================================
# Arg_1 = $# (Literally $# in the calling script)
# Arg_n = REQUIRED_ARGS
{
	arg_list=`echo $@ | cut -f2- -d\ `
	if [ "$arg_list" = "" ]
	then
		required_args=0
	else
		required_args=`s_count_args $arg_list`
	fi
	if [ $1 != $required_args ]
	then
		echo ""
		echo "Syntax Error in $0"
		echo "Usage: $0 $arg_list"
		echo ""
		exit
	else
		break
	fi
}

SQL*Net 1.0 Functions

This next group of functions were created to help with distributed database connections. They are all based on the Oracle SQL*Net 1.0 protocol. There is a matching set for SQL*Net 2.1 later in this section. To understand these functions fully, you may need to make reference to some other files listed in the last section - Putting It All Together. I will highlight this again nearer the time.


#===================================================================
s_sid_list()	# (c) RHReepe. Returns list of DB SID's on HOST
#===================================================================
# Arg_1 = [HOSTNAME:-THISHOST]
{
	tcpctl stat @${1:-$THISHOST} 2> /dev/null	| \
	grep "ORACLE SID"			| \
	cut -f2 -d:					| \
	tr ',' ' '
}
#===================================================================
s_connect_list()	# (c) RHReepe. Returns list of Global Connect Strings
#===================================================================
{
	connect_strings=""
	for next_host in $REFERENCE_DBSERVER
	do
	   list_of_database_sids=`s_sid_list $next_host`
	   for next_sid in $list_of_database_sids
	   do
	      connect_strings="$connect_strings @t:$next_host:$next_sid"
	   done
	done
	echo $connect_strings
}
#===================================================================
s_select_db()	# (c) RHReepe. Returns list DB's of TYPE
#===================================================================
# Arg_1 = DATABASE_TYPE
# Arg_2 = [DATABASE_SERVER:-THISHOST]
{
	type_list=""
	wanted_type=`s_lower $1 | cut -c1`
	database_list=`s_sid_list ${2:-$THISHOST}`
	for database in $database_list
	do
		db_type=`echo $database | grep -c "_$wanted_type"`
		if [ $db_type -gt 0 ]
		then
			type_list="$type_list $database"
		fi
	done
	echo $type_list
}

In the function s_sid_list() the stderr file (file descriptor 2) is directed to /dev/null to stop complaints of a non-running oracle server inflicting damage on crontab scripts. If a server is down it just returns a null string anstead of an error message which cron would forward to your mailbox. As almost every script of crontab job I create has a call to s_sid_list in it somewhere, this would be very tiresome. Note also that this is just a single piped command list. The back-slashes hide the newline from the shell and make printout of this function easier

The s_connect_list() function returns a complete list of global connect strings which is used for running reports on all databases from a crontab job.

The s_select_db() function allows selection of a database by type on a server. I have a few utility scripts which address particular database types only; such as test, development, master, evaluation, production, etc.

Home Next Preface Introduction Basic Shells Shell Syntax Built-In Commands Command Substitution Startup & Environment Pipes, Lists & Redirection Input & Output Using Files Design Considerations Functions Debugging Putting It All Together Appendix Code Examples
Page 212
This page was brought to you by rhreepe@injunea.demon.co.uk