if [ $# -eq 0 ]; then exec perl -x -S $0; exit $? ; else exec perl -x -S $0 "$@"; exit $? ; fi
#!/bin/perl
#optpath - eliminate path components that do not exist on this host.
#################################### MAIN ######################################
&init_pathname();
&parse_args;
&init_env($VAR_ARG, $SEP_ARG);
$newpath = "";
%upath = ();
#for each path component...
foreach $pp (@PATH)
{
#printf STDERR "pp=%s\n", $pp;
next if (defined($upaths{$pp})); #been there, done that
next if (!(-d $pp) && !(-f $pp) && $DELETE_OPTION);
if ($RM_OPT == 1) {
$yesmatch = 0;
foreach $pat (@RM_LIST) {
$yesmatch = ($pp =~ /$pat/);
#printf STDERR "pat=%s pp=%s yesmatch=%d\n", $pat, $pp, $yesmatch;
last if ($yesmatch);
}
next if ($yesmatch);
}
$upaths{$pp} = 1;
$newpath = ($newpath eq "") ? $pp : "${newpath}$SEP_ARG${pp}";
}
print "$newpath\n";
exit 0;
################################# INIT,USAGE ###################################
sub usage
{
local($status) = @_;
print STDERR <<"!";
Usage: $p [-help] [-d] -var PATHVAR -sep PATHSEP
[-rm pattern[,pattern ...]]
Synopsis:
Edit a PATH variable, eliminating redundant components,
while preserving precedence.
Options:
-help display usage message.
-d delete non-existent components from path.
-var PATHVAR
use <PATHVAR> instead of the standard command PATH variable.
-sep PATHSEP
use <PATHSEP> instead of the standard command PATH separator char.
-rm pattern[,pattern ...]
remove path components matching any pattern in the supplied
pattern list. Individual patterns are interpreted as perl
regular-expressions.
Examples:
Typical use at end of .cshrc or .tcshrc:
set opt=`$p` >& /dev/null
if (\$status == 0) then
setenv PATH \$opt
else
echo path not optimized
endif
At end of .profile (/bin/sh) or profile.ksh (mks shell):
opt=`optpath`
if [ $? -eq 0 ]; then
PATH=$opt
else
echo path not optimized
fi
Delete components that begin with "/home/d/tools",
or end with "/bin/cmn", "/bin/\$OWARE_ROOT", or "/install/bin".
Note the careful quoting. This allows the shell to interpolate
\$OWARE_ROOT, while passing \$ as part of the perl pattern:
set opt=`$p -rm '^/home/d/tools,/install/bin\$,/bin/'\${OWARE_ROOT}'\$'`
Edit the Java CLASSPATH variable, deleting non-existent
class directories and archives:
set opt=`$p -d -var CLASSPATH -sep ':'`
NOTES:
Please check the status of the $p command
before resetting your path - otherwise your shell
may become unusable.
Care must be taken with the -d option. Sometimes
path components are not present because they have
not been built yet, or because the network is
temporarily unavailable.
!
exit($status);
}
sub parse_args
#proccess command-line aguments
{
local ($flag, $parm);
$DELETE_OPTION = 0;
$RM_OPT = 0;
$SEP_OPT = 0;
$VAR_OPT = 0;
#default to standard path var & separator:
$VAR_ARG = $PATHVAR;
$SEP_ARG = $CPS;
#eat up flag args:
while ($#ARGV+1 > 0 && $ARGV[0] =~ /^-/) {
$flag = shift(@ARGV);
if ($flag eq '-d') {
$DELETE_OPTION = 1;
} elsif ($flag =~ '^-h') {
&usage(0);
} elsif ($flag eq '-var') {
if ($#ARGV < 0 || $ARGV[0] eq "") {
printf STDERR "%s: -var requires an argument\n", $p;
&usage(1);
}
$VAR_OPT = 1;
$VAR_ARG = shift(@ARGV);
} elsif ($flag eq '-sep') {
if ($#ARGV < 0 || $ARGV[0] eq "") {
printf STDERR "%s: -sep requires an argument\n", $p;
&usage(1);
}
$SEP_OPT = 1;
$SEP_ARG = shift(@ARGV);
} elsif ($flag eq '-rm') {
if ($#ARGV < 0 || $ARGV[0] eq "") {
printf STDERR "%s: -rm requires an argument\n", $p;
&usage(1);
}
$RM_OPT = 1;
@RM_LIST = split(',', shift(@ARGV));
} else {
&usage(1);
}
}
#ignore any other args...
}
sub init_env
{
local($pathvar, $pathsep) = @_;
local ($path) = $ENV{$pathvar};
#printf STDERR "init_env: OS=%d pathvar='%s'\n", $OS, $pathvar;
#convert to lower case if NT:
$path =~ tr/A-Z/a-z/ if ($OS == $NT);
#get path environment var:
@PATH = split($pathsep, $path);
if ($#PATH < 0) {
printf STDERR ("%s: can't get path variable!\n", $p);
exit(1);
}
}
################################ PATH UTILITIES ###############################
sub pickfiles
#pick the plain file entries from a directory listing.
#<lsout> must be in CWD or contain full path refs.
#list returned in <thefiles>.
{
local (*thefiles, *lsout) = @_;
@thefiles = grep(!(-d $_), @lsout);
}
sub pwd
#return full pathname of current working directory.
{
local ($tmp);
if ($OS == $UNIX) {
$tmp = (`pwd`);
chop $tmp;
return($tmp);
}
return("NULL"); #not handled
}
sub ls
#<lsout> <-- `ls <dir>`
{
local (*lsout, $dir) = @_;
if (!opendir(DIR, $dir)) {
@lsout = ();
return;
}
#skip '.' & '..' on unix
@lsout = grep(!/^\.\.?$/,readdir(DIR));
closedir(DIR);
}
sub path_separator
#what is the separator char used by this filesystem, and how is
#the current directory indicated?
#Returns 9-tuple:
# (current_dir_symbol,
# volume_separator,
# input_path_separator,
# output_path_separator,
# up_directory,
# command_PATH_env_var_separator,
# command_LIBPATH_env_var_separator,
# PATH_ENV_VAR_NAME
# )
{
$UNIX = 1; $NT=2;
$OSENV = $ENV{'OS'};
## if ((defined($OSENV) && $OSENV eq 'Windows_NT') || $0 =~ /\.ksh$/) {
## $OS = $NT;
## return('.', ':', '[\\\/]', '/', '..', ';', ';', 'PATH');
## }
#default is unix:
$OS = $UNIX;
return('.', '/', '/', '/', '..', ':', ';', 'PATH');
}
sub init_pathname
#initialize standard pathname variables.
{
($DOT, $VOLSEP, $PS_IN, $PS_OUT, $UPDIR, $CPS, $LIBPS, $PATHVAR) = &path_separator;
#set up program name argument:
local(@tmp) = split($PS_IN, $0);
# figure out the program name and put it into p
$p = $tmp[$#tmp];
$p =~ s/\.ksh$// if ($OS == $NT);
}
sub mkpathname
#convert a list of pathname components to a local path name.
{
local (@plist) = @_;
#strip trailing input path-separators:
for ($ii=0; $ii<=$#plist; $ii++) {
$plist[$ii] =~ s/${PS_IN}$//;
}
return(join($PS_OUT, @plist));
}