methods to operate on instances of class ``Path'', was: path utility functions

methods to operate on instances of class ``Path'', was: path utility functions

Post by Markus Pilzecke » Thu, 21 Oct 1999 04:00:00



Hello, path specialists,

nobody asked my, but I thought, my results may be of interest for you:

I know your news thread starting on 99-05-11 in comp.unix.shell:

    http://x41.deja.com/[S0=90179b4b1803a44,ST_rn=ps]/viewthread.xp?AN=478354613&search=thread&svcclass=dnserver&ST=PS&CONTEXT=940351141.439484500&HIT_CONTEXT=940351141.43948 arinet

and I'm somewhat curious, why there is a need for [local] variables at all.

Here is, how I solved my path processing:

-------8<------ ~/bin/path --------------------------------------
#
# shell class ``Path''
#
# implements some methods intended to operate on
# instances of this class, like ``PATH'', ``MANPATH'' or ``CLASSPATH''.
#

function  Path.rm ()
  # removes
  #   second argument ``dirname''
  #   , which is assumed to be a string specifying a single path
  # to
  #   first argument ``path''
  #   , which is assumed to be the name of a path-like variable.
  # .
  #
  # Author:


  #
  # Date:
  #   99-10-19
  #
  {
    #   eval echo \"\$\{$1\}\"        # echo variable with name $1
    #   sed 's*:'$2':*:*g'      # remove $2 from anywhere in the middle
    #   sed 's*^'$2':**g'       # remove $2 from beginning
    #   sed 's*:'$2'$**g'       # remove $2 from end
    #   sed 's*^'$2'$**g'       # remove $2, if it is the only remaining entry
    eval $1=$( eval echo \"\$\{$1\}\" | sed -e 's*:'$2':*:*g' -e 's*^'$2':**g' -e 's*:'$2'$**g' -e 's*^'$2'$**g' )
    return
  }

function  Path.prepend ()
  # prepends
  #   second argument ``prependix''
  #   , which is assumed to be a string specifying a single path
  # to
  #   first argument ``path''
  #   , which is assumed to be the name of a path-like variable.
  # .
  #
  # Did ``prependix'' already exist in ``$path''
  # , it is taken out of its former position and put in front.
  #
  # Author:

  #
  # Date:
  #   99-10-19
  #
  {
    Path.rm $1 $2
    if  [ -z $(eval echo \"\$\{$1\}\") ]
      then
        eval $1=$2
      else
        eval $1=$2":"\$\{$1\}
    fi
    return
  }

function  Path.append ()
  # appends
  #   second argument ``appendix''
  #   , which is assumed to be a string specifying a single path
  # to
  #   first argument ``path''
  #   , which is assumed to be the name of a path-like variable.
  # .
  #
  # Did ``appendix'' already exist in ``$path''
  # , it is taken out of its former position and put at end.
  #
  # Author:

  #
  # Date:
  #   99-10-19
  #
  {
    Path.rm $1 $2
    if  [ -z $(eval echo \"\$\{$1\}\") ]
      then
        eval $1=$2
      else
        eval $1=\$\{$1\}":"$2
    fi
    return
  }

-------8<------------------------------------------------------

And here is, how I use it in my .profile:

-------8<------ ~/.profile --------------------------------------

# import class ``Path'':
. path

# I'm paranoid, sorry:
umask 077

# My sysadmin thinks I do, but ...
# ... I don't ever regret anything:
unalias rm
unalias cp
unalias mv

# set various environment variables, which I occasionally need:
for p in "/opt/tex/info"
  do
  Path.prepend INFOPATH $p
  done
export INFOPATH

for p in "/opt/jdk1.2.2/bin" "/export/mp/bin" "${HOME}/bin" "."
  do
  Path.prepend "PATH" "$p"
  done

for p in "/opt/jdk1.2.2/lib/tools.jar" "/opt/jdk1.2.2/lib/dt.jar" "/opt/jdk1.2.2/src.jar" "."
  do
  Path.prepend CLASSPATH $p
  done
export CLASSPATH

for p in "/export/mp/man"
  do
  Path.prepend MANPATH $p
  done
export CLASSPATH

-------8<--------------------------------------------------------

As you see, I gave sed usage the preference over a shell-only solution.

I tested these scripts with bash-1.14, which may be too powerful
to be a real proof of [Bourne shell] minimalism.

Hope, you enjoy it,

  Markus

 
 
 

methods to operate on instances of class ``Path'', was: path utility functions

Post by Simon McClenaha » Thu, 21 Oct 1999 04:00:00


Markus Pilzecker <m...@dfki.de> wrote in message news:kp904y2ei7.fsf@dfki.de...
> and I'm somewhat curious, why there is a need for [local] variables at all.

My pathrm function ended up using ksh variable operations rather than
inefficient sed commands like you have commented out. If you found a way without
using local variables, congratulations! Too bad it's unreadable! ;-)

> Here is, how I solved my path processing:

Here's how I solved my path processing: note that I encountered a problem with
the pathclean function. I would appreciate it if someone could give me an
explanation why! And if you can rewrite these functions without using local
variables, I guess that would be nice too.

$ cat path*

-------------------------------------------------------------------

#!/bin/ksh
#$Header: /usr/local/devel/devenv/scripts/RCS/pathappend,v 1.2 1999/09/14
20:39:22 devenv Exp $
#######################################<+>#####################################
#
# $Source: /usr/local/devel/devenv/scripts/RCS/pathappend,v $
# $RCSfile: pathappend,v $
#
# Description:  ksh function to append a directory to a path variable,
#               if it exists.
#
# $Author: devenv $
# From: damer...@mmm.com (Dan Mercer)
# Newsgroups: comp.unix.shell
# Subject: Re: path utility functions
# Date: 12 May 1999 22:32:00 GMT
#
# $Log: pathappend,v $
# Revision 1.2  1999/09/14 20:39:22  devenv
# Moved pathclean to after the assignment.
# sxm
#
# Revision 1.1  1999/05/17 20:59:58  devenv
# Initial revision
#
#
#######################################<->#####################################

function pathappend
{
   # Format pathappend PATH dir
   (($# != 2)) && return
   [[ -d $2 ]] || return
   pathrm $1 $2
   eval $1=\$$1:$2
   pathclean $1

}

-------------------------------------------------------------------

#!/bin/ksh
#$Header: /usr/local/devel/devenv/scripts/RCS/pathclean,v 1.2 1999/09/10
18:58:12 devenv Exp $
#######################################<+>#####################################
#
# $Source: /usr/local/devel/devenv/scripts/RCS/pathclean,v $
# $RCSfile: pathclean,v $
#
# Description:  ksh function to clean empty entries and leading/trailing :'s
#               from a path variable.
#
# $Author: devenv $
# From: damer...@mmm.com (Dan Mercer)
# Newsgroups: comp.unix.shell
# Subject: Re: path utility functions
# Date: 12 May 1999 22:32:00 GMT
#
# $Log: pathclean,v $
# Revision 1.2  1999/09/10 18:58:12  devenv
# Commented out conditional expression that caused a long pause when run.
#
# Revision 1.1  1999/05/17 20:55:18  devenv
# Initial revision
#
#
#######################################<->#####################################

function pathclean
{
   # Format: pathclean path,  for instance pathclean MANPATH
   typeset pcl_path pcl_array IFS           # set local vars - IFS won't need
                                            # to be reset
   pcl_path=${1:-PATH}                      # provide default value
   # The following conditional expression pauses for a long time
   # eval [[ \$$pcl_path = +(:*|*::*|*:) ]] ||
   #   return                                # return if there's nothing to do
   IFS="${IFS}:"                            # add colon to IFS
   eval set -A pcl_array \$$pcl_path        # split pcl_path into pcl_array
   eval set -A pcl_array ${pcl_array[*]}    # eliminate empty pcl_array elements
   IFS=:                                    # set output file separator to colon
   eval $pcl_path="${pcl_array[*]}"         # set pcl_path

}

-------------------------------------------------------------------

#!/bin/ksh
#$Header: /usr/local/devel/devenv/scripts/RCS/pathprepend,v 1.2 1999/09/14
20:33:32 devenv Exp $
#######################################<+>#####################################
#
# $Source: /usr/local/devel/devenv/scripts/RCS/pathprepend,v $
# $RCSfile: pathprepend,v $
#
# Description:  ksh function to prepend a directory to a path variable,
#               if it exists.
#
# $Author: devenv $
# From: damer...@mmm.com (Dan Mercer)
# Newsgroups: comp.unix.shell
# Subject: Re: path utility functions
# Date: 12 May 1999 22:32:00 GMT
#
# $Log: pathprepend,v $
# Revision 1.2  1999/09/14 20:33:32  devenv
# Moved pathclean to after the assignment.
# sxm
#
# Revision 1.1  1999/05/17 20:58:03  devenv
# Initial revision
#
#
#######################################<->#####################################

function pathprepend
{
   # Format pathprepend PATH dir
   (($# != 2)) && return
   [[ -d $2 ]] || return
   pathrm $1 $2
   eval $1=$2:\$$1
   pathclean $1

}

-------------------------------------------------------------------

#!/bin/ksh
#$Header: /usr/local/devel/devenv/scripts/RCS/pathpurge,v 1.2 1999/09/14
20:26:07 devenv Exp $
#######################################<+>#####################################
#
# $Source: /usr/local/devel/devenv/scripts/RCS/pathpurge,v $
# $RCSfile: pathpurge,v $
#
# Description:  ksh function to remove duplicate entries from a path variable.
#
# $Author: devenv $
#
# $Log: pathpurge,v $
# Revision 1.2  1999/09/14 20:26:07  devenv
# Use ksh function keyword.
# Removed invalid pathrm statement.
# sxm
#
# Revision 1.1  1999/05/17 20:53:39  devenv
# Initial revision
#
#
#######################################<->#####################################

function pathpurge
{
    typeset orig_path new_path dir_array dir i ifs_hold
    eval "orig_path=\${$1}"
    ifs_hold="$IFS"
    IFS=:
    set -A dir_array $orig_path
    IFS="$ifs_hold"
    new_path=""
    let "i = ${#dir_array[*]} - 1"
    while [ "$i" -ge 0 ] ; do
        dir=${dir_array[$i]}
        if [ -n "$dir" ] ; then
            pathrm new_path $dir
            new_path=${dir}:${new_path}
        fi
        let "i = i - 1"
    done
    eval "${1}=\${new_path}"

}

-------------------------------------------------------------------

#!/bin/ksh
#$Header: /usr/local/devel/devenv/scripts/RCS/pathrm,v 1.1 1999/05/17 20:57:24
devenv Exp $
#######################################<+>#####################################
#
# $Source: /usr/local/devel/devenv/scripts/RCS/pathrm,v $
# $RCSfile: pathrm,v $
#
# Description:  ksh function to remove an entry from a path variable
#
# $Author: devenv $
# From: damer...@mmm.com (Dan Mercer)
# Newsgroups: comp.unix.shell
# Subject: Re: path utility functions
# Date: 12 May 1999 22:32:00 GMT
#
# $Log: pathrm,v $
# Revision 1.1  1999/05/17 20:57:24  devenv
# Initial revision
#
#
#######################################<->#####################################

function pathrm
{
   # Format: pathrm PATH pathelement
   typeset prm_path prm_tmp             # set local vars
   prm_path=${1:-PATH}                  # provide default value
   eval [[ :\$$prm_path: = *:$2:* ]] ||
      return                            # nothing to do
   eval prm_tmp=\":\$$prm_path:\"
   prm_tmp=${prm_tmp%:$2:*}:${prm_tmp#*:$2:}
   prm_tmp=${prm_tmp#:}
   prm_tmp=${prm_tmp%:}
   pathclean $prm_path
   eval $prm_path=\$prm_tmp             # set prm_path

}

-------------------------------------------------------------------

> And here is, how I use it in my .profile:

And here is how I use it in my .profile: (same profile used in Solaris and SCO)

It is essential to do an autoload -x on these functions, otherwise other scripts
that I source (the "dot" command) will not find these functions and do weird
things (I can't be more specific, my memory is fading).

---------------------------------------------------------------------
# First, some utility functions
FPATH=$FPATH:/usr/local/devel/devenv/scripts
export FPATH
autoload -x pathappend
autoload -x pathprepend
autoload -x pathclean
autoload -x pathpurge
autoload -x pathrm
autoload -x exportexist
pathpurge FPATH
export FPATH

# Environment variables
#######################
# normal system command path
pathappend syspath /usr/xpg4/bin
pathappend LD_LIBRARY_PATH /usr/xpg4/lib

pathappend syspath /bin
pathappend syspath /sbin
pathappend syspath /etc

pathappend syspath /usr/bin
pathappend syspath /usr/sbin
pathappend syspath /usr/lbin
pathappend syspath /usr/ibin
pathappend syspath /usr/etc
pathappend LD_LIBRARY_PATH /usr/lib
pathappend LD_LIBRARY_PATH /usr/4lib
pathappend LD_LIBRARY_PATH /usr/shlib
pathappend MANPATH /usr/catman
pathappend MANPATH /usr/man

pathappend syspath /usr/ucb
pathappend LD_LIBRARY_PATH /usr/ucblib

pathappend prodpath /usr/ccs/bin
pathappend LD_LIBRARY_PATH /usr/ccs/lib

pathappend syspath /usr/local/sbin
pathappend syspath /usr/local/bin
pathappend syspath /usr/local/etc
pathappend LD_LIBRARY_PATH /usr/local/lib
pathappend MANPATH /usr/local/man

PATH=$syspath:$PATH
export PATH

...

pathpurge PATH
export PATH
pathpurge LD_LIBRARY_PATH
export LD_LIBRARY_PATH
pathpurge MANPATH
export MANPATH

> As you see, I gave sed usage the preference over a shell-only solution.

> I tested these scripts with bash-1.14, which may be too powerful
> to be a real proof of [Bourne shell] minimalism.

Maybe we could figure out something that is both ksh and bash compatible?

cheers,
--
Simon McClenahan
Computer Consultant Extraordinaire
Whittman-Hart http://www.Whittman-Hart.com
BALR Corporation http://www.BALR.com
+1(630)575-8200

 
 
 

1. zsh's 'typeset -U path' wipes out path/PATH

I've found a bug (or at best a very perverse "feature") in zsh; it
can be illustrated by the following three short scripts:

# script_A
PATH=/usr/local/bin:/usr/bin:/bin
echo $#path
typeset -U path
echo $#path
# eof

# script_B
source script_A
# eof

# script_C
c_fxn () { source script_A }
c_fxn
# eof

Note that both the contents of script_B and the body of the function
c_fxn defined in script_C consist of the same one line, namely
"source script_A".  Now,

% source script_B
3
3
% source script_C
3
0

In words, when script_A is sourced within a script that is itself
being sourced, typeset -U path preserves the components of PATH
(or at least their number), but if script_A is sourced within the
body of a *function*, calling the function causes the expression
typeset -U path to *clear* the contents of PATH.

Please-please-please don't tell me this is a feature!  I'd lose
all faith in the designers of zsh if this turns out to be a feature!

More importantly, how does one get around this problem.  I've tried
saving the value of $path before calling 'typeset -U' on it, and
restoring it afterwards, but the results have been disastrous (I've
tried too many variants to describe them all).

kj

--
NOTE: In my address everything before the first period is backwards;
and the last period, and everything after it, should be discarded.

2. curses problem

3. Can't Alter My Path, Can't Find My Path

4. Appletalk and Solaris

5. Path as "su" doesn't equal path as root or as login user

6. AWK: index("A-Za-z",c) > 0 syntax error

7. Almost working....font path is screwing up in X (path's correct)

8. 4.1 floppies too bigs ?

9. Function to add path element to path variable

10. add in the PATH a path if not present in the PATH

11. ksh: add path to $PATH only when ot yet in $PATH

12. PATH=$(getconf PATH), but PATH for getconf?

13. set path = "$path" hoses path in tcsh -- why???