Saturday, February 2, 2008

Shell Script To Fake Linux Locate On Solaris

Hey There,

For this lazy weekend, I thought I'd put together a little shell script to address an issue I run into commonly enough.

If you've used RedHat Linux (or pretty much any Linux distro nowadays), you may have come to enjoy the convenience of the "locate" and "slocate" commands. Basically, all the command really does, in one mode, is create a database of every directory and file on a system (dated right then and there) and, in the most common usage mode, search that database file.

Adhering to these basic concepts, I wrote up a quick script to kind-of do the same thing on Solaris (As per above, this should work on pretty much any Unix system, as well).

Basically, you'll invoke it once to create file and directory databases (using simple find and ls commands), and run the generated scripts to search those text databases. This script has only 3 options:

f - to make a file-listing text database and create a built in script to emulate searching for files.
d - to make a directory-listing text database and create a built in script to emulate searching for directories.
nodat - to not create the additional tree.dat file that is only a directory database; no built-in script.

Depending upon what you want, if you were to run:

host # ./gfind f d nodat

you'd end up with two files, which you could invoke like this:

host # ./filefind FILENAME
host # ./treefind FILENAME


and these two commands would list out all the files matching your query (grep is used under the covers so you can use shortened versions of your desired search string to get back more results. It works just like locate/slocate in that when you run it (just like updatedb for locate/slocate), the results you get are what was on the system at the time you ran it.

If you opt to not include the "nodat" argument on your command line (only valid with the "d" option), the script will also create a totally separate directory database that you can run whatever crazy grep-like commands you want to against it.

Hope it helps you out to a good degree :)

Cheers,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/ksh
#
# gfind - file and directory search program producer and
# directory tree mapper
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

trap 'echo "";echo "Cleaning up and bailing out!!!";rm -f treefind filefind tree.dat johno tempmap maptemp newmap oldmap;exit' 1 2 3 15

rm -f treefind filefind tree.dat johno tempmap maptemp newmap oldmap

function make_treeexec
{
print "#!/bin/ksh" >> treefind
print "" >> treefind
print "for x" >> treefind
print "do" >> treefind
print "grep \$x treefind" >> treefind
print "done" >> treefind
print "exit" >> treefind
print "" >> treefind
chmod 777 treefind
}

function make_fileexec
{
print "#!/bin/ksh" >> filefind
print "" >> filefind
print "for x" >> filefind
print "do" >> filefind
print "grep \$x filefind" >> filefind
print "done" >> filefind
print "exit" >> filefind
print "" >> filefind
chmod 777 filefind
}

function make_filefind
{
find / -print -depth 2>/dev/null >> johno
sed '/^\proc/d' johno >> filefind
rm johno
}

function make_treefind
{
ls -R / 2>/dev/null >> tempmap
sed -n '/\//p' tempmap >> maptemp
sed -e '/^\/dos/d' -e '/^\/proc/d' maptemp >> treefind
rm tempmap
}

function make_dirtree
{
awk '{if ($0 ~ /^\/[^\/]*\/[^\/]*$/)
{print " "$0}
else if ($0 ~ /^\/[^\/]*\/[^\/]*\/[^\/]*$/)
{print " "$0}
else if ($0 ~ /^\/[^\/]*\/[^\/]*\/[^\/]*\/[^\/]*$/)
{print " "$0}
else if ($0 ~ /^\/[^\/]*\/[^\/]*\/[^\/]*\/[^\/]*\/[^\/]*$/)
{print " "$0}
else if ($0 ~ /^\/[^\/]*$/)
{print $0}
else
{print " "$0}
}' maptemp >> newmap
sed 's/^ \/[^\/]*/ /' newmap >> oldmap
sed 's/^ \/[^\/]*\/[^\/]*/ /' oldmap > newmap
sed 's/^ \/[^\/]*\/[^\/]*\/[^\/]*/ /' newmap > oldmap
sed 's/^ \/[^\/]*\/[^\/]*\/[^\/]*\/[^\/]*/ /' oldmap > newmap
sed 's/^ \/[^\/]*\/[^\/]*\/[^\/]*\/[^\/]*\/[^\/]*/ /' newmap > oldmap
rm maptemp newmap
mv oldmap tree.dat
}

if [ $# -lt 1 ] || [ $# -gt 3 ]
then
echo "Must specify at least one option!!!!"
echo ".. and no more than three..."
echo "Usage: gfind ( d ) ( f ) ( nodat )"
echo "Option \"nodat\" only valid with \"d\""
exit 1
fi
if [ $# -eq 3 ]
then
if [[ $1 = d && $2 = f && $3 = nodat ]] || [[ $1 = f && $2 = d && $3 = nodat ]] || [[ $1 = d && $2 = nodat && $3 = f ]] || [[ $1 = f && $2 = nodat && $3 = d ]] || [[ $1 = nodat && $2 = d && $3 = f ]] || [[ $1 = nodat && $2 = f && $3 = d ]]
then
make_fileexec
make_filefind
make_treeexec
make_treefind
rm -f maptemp
echo "File \"treefind\" created successfully!"
echo "File \"filefind\" created successfully!"
exit
else
echo "Hmm... Something wasn't right there"
echo "Your only options are \"d\" \"f\" or"
echo "\"nodat\", which is only good with \"d\""
exit 1
fi
fi
if [ $# -eq 2 ]
then
if [[ $1 = d && $2 = f ]] || [[ $1 = f && $2 = d ]]
then
make_fileexec
make_filefind
make_treeexec
make_treefind
make_dirtree
echo "File \"treefind\" created successfully!"
echo "File \"filefind\" created successfully!"
echo "File \"tree.dat\" created successfully!"
exit
elif [[ $1 = d && $2 = nodat ]] || [[ $1 = nodat && $2 = d ]]
then
make_treeexec
make_treefind
rm -f maptemp
echo "File \"treefind\" created successfully!"
exit
else
echo "Ooops, you can only possibly combine"
echo "\"d\" and \"f\" or \"d\" and \"nodat\""
echo "with only two options taken!!!"
exit 1
fi
fi
if [ $# -eq 1 ]
then
if [[ $1 = d ]]
then
make_treeexec
make_treefind
make_dirtree
echo "File \"treefind\" created successfully!"
echo "File \"tree.dat\" created successfully!"
exit
elif [[ $1 = f ]]
then
make_fileexec
make_filefind
echo "File \"filefind\" created successfully!"
exit
elif [[ $1 = nodat ]]
then
echo "Option \"nodat\" only works with option \"d\"!"
exit 1
else
echo "I Don't know that option!!! Try \"d\" or \"f\""
exit 1
fi
fi


, Mike