LinuxQuestions.org
LinuxAnswers - the LQ Linux tutorial section.
Go Back   LinuxQuestions.org > Blogs > rainbowsally
User Name
Password

Notices

Rate this Entry

Starting With Stat (dyn linked shell routines)

Posted 02-19-2012 at 08:51 PM by rainbowsally

Features:
  • dynamic linkage of shell subroutines
  • automatically loading shell dependencies
In order to dynamically link subroutine files we need a method of blocking multiple loads of any file.

For this, we load a set of base definitions in a file named sub.sub. The sub.sub file includes some simple functions for listing functions and the main function that blocks multiple-loading as well as a 'sub.unload <filename> function so we can unload and reload subroutines while editing them.

For this we assume the user's HOME/bin folder exists and is in the PATH *AND* that the shell is 'bash' (not Dash, ala ubuntu).

See the folder tree and how and why to make symlinks to install these things in your 'sandbox' in the previous blog entry here. (Most of these utilities will work without KDE but most DO require 'bash' as the user's default shell.)
http://www.linuxquestions.org/questi...-tofile-34376/

First let's start with a working subroutine, then we'll take a look at the sub.sub file.

file: stat.sub
purpose: display individual fields from stat and du core utils.
Code:
source sub.sub
LOADONCE stat.sub; eval "$RETURN"
 
statistics=""
 
_stat()
{
    statistics=`stat "$1"`
}


stat.mode() # filename
{
    _stat "$1"
    echo "$statistics" | sed '/Access: (/! D; s/Access: (//; s/).*//; s|/| (|; s/$/)/'
} 

# let's read the number of bytes rather than size on disk and allow KiB or MiB
# display.
stat.size() # filename
{
#    _stat "$1"
#    echo "$statistics" | sed '/.*Size:/! D; s/.*Size: //; s/ .*//'
  du -cbs $2 `echo $1` | sed '/total$/!d' | cut -f1 
}


stat.type() # filename
{
    _stat "$1"
    echo "$statistics" | sed '/.*IO Block:/! D; s/.*IO Block: [^ ]* *//'
}


stat.mtime() #filename
{
    _stat "$1"
    echo "$statistics" | sed '/Modify: /! D; s/Modify: //; s/\..*$//'
}


stat.atime() #filename
{
    _stat "$1"
    echo "$statistics" | sed '/Access: [^(]/! D; s/Access: //; s/\..*$//'
}


stat.owner() # filename  -- displays owner
{
  local filename=$1
  echo $(stat $filename) | cut -f2 -d')' | cut -f5 -d' '
  }


stat.group()   # filename  -- displays group
{
  local filename=$1
  echo $(stat $filename) | cut -f2 -d')' | cut -f5 -d' '
}


stat.mode()   # filename  -- displays mode flags (permissions)
{
  local filename=$1
  echo $(stat $filename) | cut -f2 -d'(' | cut -f1 -d'/'
}


stat.help()
{
    local R=`printf "\x1b[31m"`
    local B=`printf "\x1b[34m"`
    local N=`printf "\x1b[0m"`
echo "
$B
    stat.sub functions:
    
        $R""stat.mode$B    # filename  -- displays mode in octal and (alpha)
        $R""stat.size$B    # filename [opt] -- total in bytes. opts: -k=KiB, -m=MiB
        $R""stat.type$B    # filename  -- displays type, e.g., 'directory', 
                                'symbolic link', or 'regular file', etc.
        $R""stat.owner$B   # filename  -- displays owner
        $R""stat.group$B   # filename  -- displays group
        $R""stat.mode$B    # filename  -- displays mode flags (permissions)
    
        $R""stat.mtime$B   # filename  -- displays time last modified or created.
        $R""stat.atime$B   # filename  -- displays time last accessed.
        
$N
"
}
And here's the brain, 'sub.sub'

Code:
# These subroutines use dots in names.  If your shell doesn't like them
# try calling bash explicitly first, then 'source <filename>'

LOADONCE() #filename -- eval "$RETURN" blocks loading a file more than once
{
    local file=`basename "$1"`
    local class=`basename "$1" |sed 's/\..*//;s/-/_/g'`
    local class_string="$class""_loaded"
    
#   LOADONCE() note: Use LOADONCE first thing! after 'source sub.sub'
#   See example below
    
    ########################################################
    # We need a string we can execute from bash's top level 
    # so that a 'return' jumps out of the currently loading 
    # file.  We can't use 'exit' or the program will end and
    # we can't use 'return' inside a subroutine because it 
    # will continue loading, so executing a $RETURN to
    # control loading is apparently the best we can do.
    ########################################################
    
#--------------------------------------------
RETURN=`cat <<_EOF
if [ "\\$$class_string" != "" ];then
    # echo "(Note: $file already loaded)" ### enable this only when debugging
    return
fi
echo "loading $file"
$class_string="TRUE"
RETURN=""
_EOF`
#--------------------------------------------

}

sub.loaded()
{
    declare |sed 's/[ =\$].*//; /_loaded/! D' 
}

UNLOADONCE() #filename -- allows reloading LOADONCE files one time
{
    for class_string in `sub.loaded`
    do
        if [ "$class_string" != "_loaded" ];then
        eval "local tmp=\$$class_string"
        if [ "$tmp" != "" ];then
        echo "(resetting: $class_string flag)"
        eval "$class_string=\"\"" 2>/dev/null
        fi
        fi
    done    
}


LOADONCE sub.sub; eval "$RETURN"    # see LOADONCE() note above

#####################################################################


bp() # param -- a simple temp breakpoint utility
{ 
    local key=""
    echo "breakpoint $1" 
    read key; 
}

sub.unload() # [filename]
{
    UNLOADONCE $@
}


_sub_sedsafe() # "string" -- returns string with sed commands escaped
{
    # Converts ".+-*/(){|}[]$^"
    echo "$1" | sed 's/\./\\\./g;  s/\+/\\\+/g; s/\-/\\\-/g; s/\*/\\\*/g; s/\//\\\//g; s/\x28/\\\x28/g;  s/\x29/\\\x29/g; s/\x7b/\\\x7b/g; s/\x7c/\\\x7c/g; s/\x7d/\\\x7d/g; s/\[/\\[/g; s/\]/\\]/g; s/\$/\\$/g;  s/\^/\\^/g;'
}    


func.make_list() # -- list all loaded funcs including system stuff
{ 
    declare -f |sed "/()/! D; /^ /D"; 
}

func.listall() # -- list all functions in all contexts
{
    func.make_list
}


func.list() # substr -- find functions with names matching substr
{
    if [ "$1" != "" ];then
        a=`func.make_list | sed "/$1/! D"`
    else
        a=`func.make_list`
    fi
    echo "$a"
}


sub.make_list() # -- makes a list of sub functions in '.sub' files
{
    grep \(\) ~/bin/*.sub |sed "s|$HOME/bin/||; /: / D; s/:/:  /"
}


sub.listall() # -- list all subs in ~/bin with 1 commentline
{
    sub.make_list > ~/bin/tofile.tmp
    edit ~/bin/tofile.tmp
}


sub.list() # [substr] -- list subs, with optional search substr
{
    local list=`sub.make_list`
    if [ "$1" != "" ];then
        echo "$list" | sed "/$1/!D" > ~/bin/tofile.tmp
    else
        echo "$list" > ~/bin/tofile.tmp
    fi
    edit ~/bin/tofile.tmp
}


sub.edit() # subname -- open ~/bin/subname.sub in editor
{
    local name=`basename $1 .sub`
    edit ~/bin/$name.sub
}


sub.locate() # funcname -- locate functions with names matching funcname
{
    grep $1 ~/bin/*.sub > ~/bin/tofile.tmp
    edit ~/bin/tofile.tmp
}


sub.show_allfuncs() # -- shows all functions innerds
{
    declare -f > ~/tofile.tmp
    edit ~/tofile.tmp
}


sub.showhelp() # subName [funcName]
{
    local subName="$1"
    shift
    
    echo    
    if [ "$1" = "" ];then
        echo    
        echo "List of functions:" 
        echo
        func.list `basename $subName ".sub"`
        echo
        echo "Type '<class>.help <class>.funcName' for brief descr of exact function"
    else
        local fnname=`_sub_sedsafe "$1"`
        grep "$fnname" ~/bin/$subName | sed '/^ /D;'
    fi
    echo

}

sub.tofile() # command args -- sends output to file and opens using 'edit'
{
    $@ >~/tofile.tmp
    edit ~/tofile.tmp
}


sub.help()
{
    sub.showhelp sub.sub $1
}
As explained in previous blog entries, these two files go into the folder here.
Code:
HOME
  \_ bin
      \_ src
          \_ subs -- all *.sub files
And they are installed with 'new.symlink' by cd-ing into the directory and
typing:
Code:
new.symlink sub.sub ~/bin
new.symlink stat.sub ~/bin
To load the stat functions type 'source stat.sub'

If you want to edit the files you can 'edit ~/stat.sub'. To unload after editing you can type 'sub.unload <filename>' and then reload it with the 'source' command.

The stat function goes a little overboard on the 'stat.help' function but you might like it.

Here are some displays of some stat and sub functions.
Code:
$> source stat.sub
loading sub.sub
loading stat.sub
-------------------
$> sub.help
List of functions:
  _sub_sedsafe () 
  sub.edit () 
  sub.help () 
  sub.list () 
  sub.listall () 
  sub.loaded () 
  sub.locate () 
  sub.make_list () 
  sub.show_allfuncs () 
  sub.showhelp () 
  sub.tofile () 
  sub.unload () 

  Type '<class>.help <class>.funcName' for brief descr of exact function
-------------------
$> stat.help

    stat.sub functions:                                                                      
                                                                                                   
        stat.mode    # filename  -- displays mode in octal and (alpha)                             
        stat.size    # filename [opt] -- total in bytes. opts: -k=KiB, -m=MiB                      
        stat.type    # filename  -- displays type, e.g., 'directory',                              
                                'symbolic link', or 'regular file', etc.                           
        stat.owner   # filename  -- displays owner                                                 
        stat.group   # filename  -- displays group                                                 
        stat.mode    # filename  -- displays mode flags (permissions)                              
                                                                                                   
        stat.mtime   # filename  -- displays time last modified or created.                        
        stat.atime   # filename  -- displays time last accessed.                                   
More dynamically linked subroutines coming up a bit later.

:-)
Posted in Uncategorized
Views 688 Comments 0
« Prev     Main     Next »
Total Comments 0

Comments

 

  



All times are GMT -5. The time now is 06:18 PM.

Main Menu
Advertisement

My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration