2008-09-25 14 views
8

Es ist typisch, so etwas in Ihrer cshrc Datei zu haben, um den Pfad einstellen:Wie aus Duplizieren Pfadvariablen in csh halten

set path = (. $otherpath $path) 

aber, wird der Pfad dupliziert, wenn Sie Ihre cshrc Datei mehrfach Quelle , wie verhinderst du die Vervielfältigung?

EDIT: Dies ist eine unsaubere Art und Weise tun:

set localpaths = (. $otherpaths) 
echo ${path} | egrep -i "$localpaths" >& /dev/null 
if ($status != 0) then 
    set path = (. $otherpaths $path) 
endif 
+0

Verwandte (obwohl meist Bourne Shell-Antworten): http://StackOverflow.com/Questions/273909/How-do-Imanipulate-Path-Elements-in-Shell-Scripts – dmckee

+1

Sie sollten Ihre Methode als separate veröffentlichen Antwort, nicht als Frage bearbeiten. –

Antwort

3

Sie folgende Perl-Skript verwenden Pfade von Duplikaten zu beschneiden.


#!/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; 
    } 
} 

ich hoffe, das ist nützlich.

+0

oops .. habe nicht bemerkt, dass ich alle meine Kommentare drin gelassen habe ... es ist alles gut. (BTW Danke nochmals Tim) :) – ShoeLace

0

Ich habe immer meinen Weg von Grund auf in .cshrc. dass ich mit einem Basispfad beginnen ist, so etwas wie:

set path = (. ~/bin /bin /usr/bin /usr/ucb /usr/bin/X11) 

(je nach System).

Und dann tun:

set path = ($otherPath $path) 

mehr Material kann hinzufügen

+0

Sie verlieren (alle Updates zu) die Systemeinstellungen. – musiphil

4

ok, nicht in csh, aber das ist, wie ich $ HOME/bin auf meinem Weg in bash anhängen ...

case $PATH in 
    *:$HOME/bin | *:$HOME/bin:*) ;; 
    *) export PATH=$PATH:$HOME/bin 
esac 

abschmecken ...

2

Ich habe wurde die folgende (Bourne/Korn/POSIX/Bash) Skript für die meisten von einem Jahrzehnt mit:

: "@(#)$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; 
}' 

In Korn-Shell, die ich benutze:

Dies hinterlässt mich mit PATH, die die neuen und anderen bin-Verzeichnisse an der Front sowie eine Kopie jedes Verzeichnisnamens im Hauptpfad enthält, außer dass die alten und extra bin-Verzeichnisse entfernt wurden.

Sie müssten dies an C-Shell anpassen (sorry - aber ich bin ein großer Gläubiger in den Wahrheiten bei C Shell Programming Considered Harmful ausgesprochen). In erster Linie müssen Sie nicht mit dem Doppelpunkttrenner herumspielen, also ist das Leben tatsächlich einfacher.

2

Nun, wenn Sie interessiert nicht, was bestellen Sie Ihre Pfade in sind, können Sie so etwas wie tun könnte:

set path=(`echo $path | tr ' ' '\n' | sort | uniq | tr '\n' ' '`) 

Das Ihre Wege sortieren wird und entfernen Sie alle zusätzlichen Pfade, die die gleichen sind. Wenn Sie haben . In deinem Pfad möchtest du es vielleicht mit grep -v entfernen und am Ende neu hinzufügen.Hier

+0

Das einzige Problem, das ich sehe, ist, dass es die Pfadreihenfolge ändern wird, aber ich mag die Tatsache, dass es ein Einzeiler ist. –

2

ist ein langer Einzeiler ohne Sortierung.
set path = (echo $path | tr ' ' '\n' | perl -e 'while (<>) { print $_ unless $s{$_}++; }' | tr '\n' ' ')

1

dr_peper,

ich in der Regel bleiben lieber zu Scripting-Fähigkeiten der Schale, in der ich leben Macht es tragbarer. Also, ich mochte Ihre Lösung mit Csh-Scripting. Ich habe es einfach erweitert, um per Dir in den Localdirs zu arbeiten, damit es für mich selbst funktioniert.

 
foreach dir ($localdirs) 
    echo ${path} | egrep -i "$dir" >& /dev/null 
    if ($status != 0) then 
     set path = ($dir $path) 
    endif 
end 
13

Im überraschte niemand die tr ":" "\n" | grep -x techique wenn ein bestimmte Ordner bereits in $ PATH existiert zur Suche verwendet. Irgendein Grund, nicht zu?

In 1 Zeile:

if ! $(echo "$PATH" | tr ":" "\n" | grep -qx "$dir") ; then PATH=$PATH:$dir ; fi 

Hier ist eine Funktion ive gemacht, mich zu $ ​​PATH (use "aaa: bbb: ccc" Notation als Argument) auf einmal mehrere Ordner hinzufügen, von denen jeder für Duplikatsprüfung vor der Zugabe:

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" 
} 

Es kann in einem Skript wie folgt aufgerufen werden:

append_path "/test:$HOME/bin:/example/my dir/space is not an issue" 

Es hat die follo wing Vorteile:

  • Keine Bashismen oder irgendeine Shell-spezifische Syntax. Es läuft perfekt mit !#/bin/sh (ive mit Bindestrich getestet)
  • mehr Ordner auf einmal
  • keine Sortierung hinzugefügt werden können, bewahrt Ordner um
  • Angebote perfekt mit Leerzeichen in Ordnernamen
  • Ein einzelner Test egal funktioniert, wenn $ Ordner ist am Anfang, Ende, Mitte, oder ist der einzige Ordner in $ PATH (damit vermeiden, x: *, *: x, : x:, x, wie viele der Lösungen hier implizit tun)
  • Funktioniert (und bewahrt), wenn $ PATH mit ":" beginnt oder endet oder "::" enthält (dh aktueller Ordner)
  • Kein awk oder sed benötigt.
  • EPA freundlich;) Original IFS-Wert wird beibehalten, und alle anderen Variablen sind lokal für den Funktionsumfang.

Hoffe, dass hilft!

+0

+! Das ist im Wesentlichen, was ich gemacht habe, und es funktioniert großartig! –

2

Verwenden von sed (1) zum Entfernen von Duplikaten.

$ PATH=$(echo $PATH | sed -e 's/$/:/;s/^/:/;s/:/::/g;:a;s#\(:[^:]\{1,\}:\)\(.*\)\1#\1\2#g;ta;s/::*/:/g;s/^://;s/:$//;') 

Dadurch werden die Duplikate nach der ersten Instanz entfernen, die möglicherweise oder möglicherweise nicht, was Sie wollen, z.B .:

$ 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 
$ 

Viel Spaß!

1

Hier ist, was ich - vielleicht jemand anderes wird es nützlich:

#!/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";' 
0

Ich habe das gleiche Bedürfnis wie die ursprüngliche Frage. Aufbauend auf Ihre bisherigen Antworten, die ich in Korn/POSIX/Bash verwendet haben:

export PATH=$(perl -e 'print join ":", grep {!$h{$_}++} split ":", "'$otherpath:$PATH\") 

ich Schwierigkeiten hatte es in csh (csh Flucht Regeln sind verrückt) direkt zu übersetzen. Ich habe verwendet (wie von dr_pepper vorgeschlagen):

set path = (`echo $otherpath $path | tr ' ' '\n' | perl -ne 'print $_ unless $h{$_}++' | tr '\n' ' '`) 

Haben Sie Ideen haben, es zu vereinfachen mehr (die Anzahl der Leitungen reduzieren)?