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 instead of the standard command PATH variable. -sep PATHSEP use 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. # must be in CWD or contain full path refs. #list returned in . { 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 # <-- `ls ` { 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)); }