path - valor - variable de entorno fms_home
Cómo evitar la duplicación de la variable de ruta en csh (11)
Es típico tener algo así en su archivo cshrc para establecer la ruta:
set path = ( . $otherpath $path )
pero, la ruta se duplica cuando obtiene su archivo cshrc varias veces, ¿cómo evita la duplicación?
EDITAR: Esta es una forma inmunda de hacerlo:
set localpaths = ( . $otherpaths )
echo ${path} | egrep -i "$localpaths" >& /dev/null
if ($status != 0) then
set path = ( . $otherpaths $path )
endif
Siempre establezco mi camino desde cero en .cshrc. Es decir, empiezo con un camino básico, algo así como:
set path = (. ~/bin /bin /usr/bin /usr/ucb /usr/bin/X11)
(dependiendo del sistema).
Y luego hazlo:
set path = ($otherPath $path)
para agregar más cosas
ok, no en csh, pero así es como agrego $ HOME / bin a mi ruta en bash ...
case $PATH in
*:$HOME/bin | *:$HOME/bin:* ) ;;
*) export PATH=$PATH:$HOME/bin
esac
Sazone al gusto...
He estado usando el siguiente script (Bourne / Korn / POSIX / Bash) durante la mayor parte de una década:
: "@(#)$Id: clnpath.sh,v 1.6 1999/06/08 23:34:07 jleffler Exp $"
#
# Print minimal version of $PATH, possibly removing some items
case $# in
0) chop=""; path=${PATH:?};;
1) chop=""; path=$1;;
2) chop=$2; path=$1;;
*) echo "Usage: `basename $0 .sh` [$PATH [remove:list]]" >&2
exit 1;;
esac
# Beware of the quotes in the assignment to chop!
echo "$path" |
${AWK:-awk} -F: ''#
BEGIN { # Sort out which path components to omit
chop="''"$chop"''";
if (chop != "") nr = split(chop, remove); else nr = 0;
for (i = 1; i <= nr; i++)
omit[remove[i]] = 1;
}
{
for (i = 1; i <= NF; i++)
{
x=$i;
if (x == "") x = ".";
if (omit[x] == 0 && path[x]++ == 0)
{
output = output pad x;
pad = ":";
}
}
print output;
}''
En shell Korn, utilizo:
export PATH=$(clnpath /new/bin:/other/bin:$PATH /old/bin:/extra/bin)
Esto me deja con PATH que contiene los directorios nuevos y otros bin en la parte delantera, más una copia de cada nombre de directorio en el valor de la ruta principal, excepto que los directorios bin viejos y adicionales han sido eliminados.
Tendría que adaptar esto a C shell (lo siento, pero soy un gran creyente en las verdades enunciadas en C Shell Programming Considered Harmful ). En primer lugar, no tendrá que jugar con el separador de colon, por lo que la vida es realmente más fácil.
puede usar el siguiente script Perl para eliminar rutas de duplicados.
#!/usr/bin/perl
#
# ^^ ensure this is pointing to the correct location.
#
# Title: SLimPath
# Author: David "Shoe Lace" Pyke <[email protected] >
# : Tim Nelson
# Purpose: To create a slim version of my envirnoment path so as to eliminate
# duplicate entries and ensure that the "." path was last.
# Date Created: April 1st 1999
# Revision History:
# 01/04/99: initial tests.. didn''t wok verywell at all
# : retreived path throught ''$ENV'' call
# 07/04/99: After an email from Tim Nelson <[email protected]> got it to
# work.
# : used ''push'' to add to array
# : used ''join'' to create a delimited string from a list/array.
# 16/02/00: fixed cmd-line options to look/work better
# 25/02/00: made verbosity level-oriented
#
#
use Getopt::Std;
sub printlevel;
$initial_str = "";
$debug_mode = "";
$delim_chr = ":";
$opt_v = 1;
getopts("v:hd:l:e:s:");
OPTS: {
$opt_h && do {
print "/n$0 [-v level] [-d level] [-l delim] ( -e varname | -s strname | -h )";
print "/nWhere:";
print "/n -h This help";
print "/n -d Debug level";
print "/n -l Delimiter (between path vars)";
print "/n -e Specify environment variable (NB: don''t include /$ sign)";
print "/n -s String (ie. $0 -s /$PATH:/looser/bin/)";
print "/n -v Verbosity (0 = quiet, 1 = normal, 2 = verbose)";
print "/n";
exit;
};
$opt_d && do {
printlevel 1, "You selected debug level $opt_d/n";
$debug_mode = $opt_d;
};
$opt_l && do {
printlevel 1, "You are going to delimit the string with /"$opt_l/"/n";
$delim_chr = $opt_l;
};
$opt_e && do {
if($opt_s) { die "Cannot specify BOTH env var and string/n"; }
printlevel 1, "Using Environment variable /"$opt_e/"/n";
$initial_str = $ENV{$opt_e};
};
$opt_s && do {
printlevel 1, "Using String /"$opt_s/"/n";
$initial_str = $opt_s;
};
}
if( ($#ARGV != 1) and !$opt_e and !$opt_s){
die "Nothing to work with -- try $0 -h/n";
}
$what = shift @ARGV;
# Split path using the delimiter
@dirs = split(/$delim_chr/, $initial_str);
$dest;
@newpath = ();
LOOP: foreach (@dirs){
# Ensure the directory exists and is a directory
if(! -e ) { printlevel 1, "$_ does not exist/n"; next; }
# If the directory is ., set $dot and go around again
if($_ eq ''.'') { $dot = 1; next; }
# if ($_ ne `realpath $_`){
# printlevel 2, "$_ becomes ".`realpath $_`."/n";
# }
undef $dest;
#$_=Stdlib::realpath($_,$dest);
# Check for duplicates and dot path
foreach $adir (@newpath) { if($_ eq $adir) {
printlevel 2, "Duplicate: $_/n";
next LOOP;
}}
push @newpath, $_;
}
# Join creates a string from a list/array delimited by the first expression
print join($delim_chr, @newpath) . ($dot ? $delim_chr."./n" : "/n");
printlevel 1, "Thank you for using $0/n";
exit;
sub printlevel {
my($level, $string) = @_;
if($opt_v >= $level) {
print STDERR $string;
}
}
espero que sea útil.
Bueno, si no te importa en qué orden están tus rutas, podrías hacer algo como:
set path=(`echo $path | tr '' '' ''/n'' | sort | uniq | tr ''/n'' '' ''`)
Eso ordenará tus caminos y eliminará todos los caminos adicionales que sean iguales. Si usted tiene . en su camino, es posible que desee eliminarlo con grep -v y volver a agregarlo al final.
Aquí hay un largo delineador sin clasificación:
set path = ( echo $path | tr '' '' ''/n'' | perl -e ''while (<>) { print $_ unless $s{$_}++; }'' | tr ''/n'' '' ''
)
dr_peper,
Por lo general, prefiero mantener las capacidades de escritura del caparazón en el que vivo. Lo hace más portátil. Por lo tanto, me gustó tu solución usando scripts csh. Acabo de extenderlo para que funcione en cada dir en localdirs para que funcione por mí mismo.
foreach dir ( $localdirs ) echo ${path} | egrep -i "$dir" >& /dev/null if ($status != 0) then set path = ( $dir $path ) endif end
Usando sed (1) para eliminar duplicados.
$ PATH=$(echo $PATH | sed -e ''s/$/:/;s/^/:/;s/:/::/g;:a;s#/(:[^:]/{1,/}:/)/(.*/)/1#/1/2#g;ta;s/::*/:/g;s/^://;s/:$//;'')
Esto eliminará los duplicados después de la primera instancia, que puede ser o no lo que desea, por ejemplo:
$ NEWPATH=/bin:/usr/bin:/bin:/usr/local/bin:/usr/local/bin:/bin
$ echo $NEWPATH | sed -e ''s/$/:/; s/^/:/; s/:/::/g; :a; s#/(:[^:]/{1,/}:/)/(.*/)/1#/1/2#g; t a; s/::*/:/g; s/^://; s/:$//;''
/bin:/usr/bin:/usr/local/bin
$
¡Disfrutar!
Esto es lo que uso: quizás alguien más lo encuentre útil:
#!/bin/csh
# ABSTRACT
# /bin/csh function-like aliases for manipulating environment
# variables containing paths.
#
# BUGS
# - These *MUST* be single line aliases to avoid parsing problems apparently related
# to if-then-else
# - Aliases currently perform tests in inefficient in order to avoid parsing problems
# - Extremely fragile - use bash instead!!
#
# AUTHOR
# J. P. Abelanet - 11/11/10
# Function-like alias to add a path to the front of an environment variable
# containing colon ('':'') delimited paths, without path duplication
#
# Usage: prepend_path ENVVARIABLE /path/to/prepend
alias prepend_path /
''set arg2="/!:2"; if ($?/!:1 == 0) setenv /!:1 "$arg2"; if ($?/!:1 && $/!:1 !~ {,*:}"$arg2"{:*,}) setenv /!:1 "$arg2":"$/!:1";''
# Function-like alias to add a path to the back of any environment variable
# containing colon ('':'') delimited paths, without path duplication
#
# Usage: append_path ENVVARIABLE /path/to/append
alias append_path /
''set arg2="/!:2"; if ($?/!:1 == 0) setenv /!:1 "$arg2"; if ($?/!:1 && $/!:1 !~ {,*:}"$arg2"{:*,}) setenv /!:1 "$/!:1":"$arg2";''
Tengo la misma necesidad que la pregunta original. Sobre la base de sus respuestas anteriores, he utilizado en Korn / POSIX / Bash:
export PATH=$(perl -e ''print join ":", grep {!$h{$_}++} split ":", "''$otherpath:$PATH/")
Tuve dificultades para traducirlo directamente en csh (las reglas de escape csh son una locura). He usado (como lo sugiere dr_pepper):
set path = ( `echo $otherpath $path | tr '' '' ''/n'' | perl -ne ''print $_ unless $h{$_}++'' | tr ''/n'' '' ''`)
¿Tiene ideas para simplificarlo más (reducir el número de tuberías)?
Estoy sorprendido de que nadie usara el tr ":" "/n" | grep -x
tr ":" "/n" | grep -x
techique para buscar si una carpeta determinada ya existe en $ PATH. ¿Alguna razón para no hacerlo?
En 1 línea:
if ! $(echo "$PATH" | tr ":" "/n" | grep -qx "$dir") ; then PATH=$PATH:$dir ; fi
Esta es una función que he hecho para agregar varias carpetas a la vez a $ PATH (use la notación "aaa: bbb: ccc" como argumento), comprobando cada una de ellas para ver si hay duplicados antes de agregar:
append_path()
{
local SAVED_IFS="$IFS"
local dir
IFS=:
for dir in $1 ; do
if ! $( echo "$PATH" | tr ":" "/n" | grep -qx "$dir" ) ; then
PATH=$PATH:$dir
fi
done
IFS="$SAVED_IFS"
}
Se puede invocar en un script como este:
append_path "/test:$HOME/bin:/example/my dir/space is not an issue"
Tiene las siguientes ventajas:
- Sin bashisms ni ninguna sintaxis específica del shell. Se ejecuta perfectamente con
!#/bin/sh
(ive probado con guión) - Se pueden agregar varias carpetas a la vez
- Sin clasificación, conserva el orden de las carpetas
- Trata perfectamente con espacios en los nombres de las carpetas
- Una sola prueba funciona sin importar si $ folder está en principio, final, medio, o es la única carpeta en $ PATH (evitando así probar x: *, *: x,: x:, x, como muchas de las soluciones aquí implícitamente) hacer)
- Funciona (y preserva) si $ PATH comienza o finaliza con ":", o tiene "::" en él (es decir, la carpeta actual)
- No necesita
awk
osed
. - Respetuoso con la EPA;) Se conserva el valor IFS original, y todas las demás variables son locales para el alcance de la función.
¡Espero que ayude!