Frage

Typischerweise enthält Ihre cshrc-Datei zum Festlegen des Pfads Folgendes:

set path = ( . $otherpath $path )

Der Pfad wird jedoch dupliziert, wenn Sie Ihre cshrc-Datei mehrmals als Quelle verwenden. Wie verhindern Sie die Duplizierung?

BEARBEITEN:Dies ist eine unreine Art, es zu tun:

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

Lösung

können Sie den folgenden Perl-Skript verwenden Pfade von Dubletten bereinigt werden soll.


#!/usr/bin/perl
#
# ^^ ensure this is pointing to the correct location.
#
# Title:    SLimPath
# Author:   David "Shoe Lace" Pyke <eselle@users.sourceforge.net >
#   :   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 <wayland@ne.com.au> 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.

Andere Tipps

Ich bin überrascht, dass niemand das benutzt hat tr ":" "\n" | grep -x Technik zum Suchen, ob ein bestimmter Ordner bereits in $PATH vorhanden ist.Gibt es einen Grund, es nicht zu tun?

In 1 Zeile:

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

Hier ist eine Funktion, die ich selbst erstellt habe, um mehrere Ordner gleichzeitig zu $PATH hinzuzufügen (verwenden Sie die Notation „aaa:bbb:ccc“ als Argument) und jeden einzelnen Ordner vor dem Hinzufügen auf Duplikate überprüft:

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 folgende Vorteile:

  • Keine Bashismen oder Shell-spezifische Syntax.Es läuft perfekt mit !#/bin/sh (ich habe es mit Dash getestet)
  • Es können mehrere Ordner gleichzeitig hinzugefügt werden
  • Keine Sortierung, Ordnerreihenfolge bleibt erhalten
  • Kommt perfekt mit Leerzeichen in Ordnernamen zurecht
  • Ein einzelner Test funktioniert unabhängig davon, ob sich $folder am Anfang, am Ende oder in der Mitte befindet oder der einzige Ordner in $PATH ist (wodurch das Testen von x:*, *:x, :X:, x, wie es viele der Lösungen hier implizit tun)
  • Funktioniert (und bleibt erhalten), wenn $PATH mit „:“ beginnt oder endet oder „::“ enthält (d. h. aktueller Ordner).
  • NEIN awk oder sed erforderlich.
  • EPA-freundlich ;) Der ursprüngliche IFS-Wert bleibt erhalten und alle anderen Variablen sind lokal im Funktionsbereich.

Hoffentlich hilft das!

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

Ich habe mit der folgenden (Bourne / Korn / POSIX / Bash) Skript für die meisten von einem Jahrzehnte:

:   "@(#)$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 der Korn-Shell, die ich benutze:

export PATH=$(clnpath /new/bin:/other/bin:$PATH /old/bin:/extra/bin)

Dies läßt mich mit PATH die neuen und andere sind-Verzeichnisse auf der Vorderseite enthält, und eine Kopie jeden Verzeichnisnamen in dem Hauptweg, ausgenommen, dass die alten und extra sind Verzeichnisse sind entfernt.

Sie müßten dies (leider C-Shell anzupassen - aber ich bin ein großer Gläubiger in den Wahrheiten unter C Shell Programmierung als schädlich ). In erster Linie werden Sie nicht mit dem Doppelpunkt Separator zur Geige, also das Leben ist tatsächlich einfacher.

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 wird Ihre Wege sortieren und entfernen Sie alle zusätzlichen Pfade, die die gleichen sind. Wenn Sie haben . in Ihrem Pfad, können Sie es mit einem grep -v entfernen und erneut hinzufügen am Ende.

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

dr_peper,

Ich ziehe es in der Regel zu Scripting-Fähigkeiten der Schale zu halten, in der ich leben. Macht es mehr tragbar. Also, ich mochte Ihre Lösung csh Scripting. Ich streckte es gerade in dem localdirs pro dir zu arbeiten, um es für mich zu arbeiten.

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

Mit sed (1) Duplikate zu entfernen.

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

Damit wird die Duplikate nach der ersten Instanz entfernen, was sein kann oder auch nicht, was Sie wollen, z.

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

Genießen Sie!

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";'

Ich habe immer meinen Weg von Grund auf in .cshrc. Das heißt ich mit einem Basispfad beginnen, 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 hinzuzufügen

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

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

ich Schwierigkeiten hatte, es zu übersetzen direkt in csh (csh Flucht Regeln sind verrückt). 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 zu vereinfachen es mehr (die Anzahl der Leitungen reduzieren)?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top