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.
- A function encapsulates a small piece of code
that will be used often.
- You only need to define it once.
- A function will execute faster than the equivalent
code in the script.
- Parameters are passed into the function via numbered
arguments just like scripts.
- 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.
- 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.
- Variables used and set inside a function can be
visible from the calling script and
- 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.
- Functions can be nested to any depth - well I haven't
found a limit.
- 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.
- 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.
#===================================================================
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
}
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.
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 $1 | Get 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.
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!
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
}
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.
|