سؤال

ومن المعتاد أن يكون شيئا مثل هذا في cshrc الملف لتحديد المسار:

set path = ( . $otherpath $path )

ولكن المسار يحصل تكرار عند المصدر الخاص بك cshrc الملف عدة مرات ، كيف يمكنك منع الازدواجية ؟

تحرير:هذا هو واحد نجس طريقة للقيام بذلك:

set localpaths = ( . $otherpaths )
echo ${path} | egrep -i "$localpaths" >& /dev/null
if ($status != 0) then
    set path = ( . $otherpaths $path )
endif
هل كانت مفيدة؟

المحلول

يمكنك استخدام التالية Perl تقليم مسارات من التكرارات.


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

آمل أن يكون مفيدا.

نصائح أخرى

متفاجئة لا أحد يستخدم tr ":" "\n" | grep -x techique أن البحث إذا كان المجلد موجود بالفعل في $PATH.أي سبب ؟

في 1 خط:

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

هنا هي وظيفة لقد جعلت نفسي لإضافة عدة مجلدات في آن واحد $PATH (استخدام "aaa:bbb:ccc" التدوين في حجة) ، والتحقق من كل واحد عن التكرارات قبل أن يضيف:

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

يمكن أن يطلق عليه في السيناريو مثل هذا:

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

فمن لديه المزايا التالية:

  • لا bashisms أو أي قذيفة محددة بناء الجملة.تشغيله تماما مع !#/bin/sh (إيف اختبار مع اندفاعة)
  • مجلدات متعددة يمكن أن تضاف في وقت واحد
  • لا يصنف ويحافظ على مجلد النظام
  • صفقات تماما مع مسافات في أسماء المجلدات
  • اختبار واحد يعمل لا يهم إذا $في مجلد في شراييني, نهاية, الأوسط, أو هو فقط في مجلد $PATH (وبالتالي تجنب اختبار x:*, *:x ، :×:, x, كما أن العديد من الحلول هنا ضمنا تفعل)
  • يعمل (والحفاظ على) إذا $PATH يبدأ أو ينتهي ب": "أو "::" في ذلك (يعني المجلد الحالي)
  • لا awk أو sed الحاجة.
  • وكالة حماية البيئة الصديقة؛) الأصلي IFS قيمة الحفاظ على جميع المتغيرات الأخرى المحلية إلى نطاق وظيفة.

على أمل أن يساعد!

حسنا ، لا في csh, ولكن هذا هو كيف لي أن إلحاق $HOME/بن على طريقي في سحق...

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

الموسم الى الذوق...

لقد تم استخدام التالية (بورن/كورن/POSIX/Bash) السيناريو لأكثر من عقد من الزمن:

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

في Korn shell, يمكنني استخدام:

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

وهذا يترك لي مع مسار تحتوي الجديدة وغيرها من بن الدلائل في الجبهة ، بالإضافة إلى نسخة واحدة من كل اسم الدليل في الطريق الرئيسي القيمة ، باستثناء القديم إضافية بن الدلائل بن إزالتها.

قد تضطر إلى التكيف مع هذا ج قذيفة (آسف ولكن أنا مؤمن كبير في الحقائق المنصوص عليها في ج قذيفة البرمجة تعتبر ضارة).في المقام الأول, لن تضطر إلى عزف مع القولون فاصل ، لذلك الحياة هو في الواقع أسهل.

حسنا, إذا كنت لا تهتم ما هو ترتيب المسارات الخاصة بك في, هل يمكن أن تفعل شيئا مثل:

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

أنه سيتم فرز المسارات الخاصة بك وإزالة أية مسارات إضافية هي نفسها.إذا كان لديك .في المسار الخاص بك, قد ترغب في إزالته مع grep -v وإعادة إضافته في نهاية المطاف.

هنا هو واحد طويل-بطانة من دون الفرز:
تعيين مسار = ( echo $path | tr ' ' '\n' | perl -e 'while (<>) { print $_ unless $s{$_}++; }' | tr '\n' ' ')

dr_peper,

وعادة ما يفضلون التمسك قدرات البرمجة قذيفة أنا أعيش في.يجعلها أكثر المحمولة.لذا أحببت الحل الخاص بك باستخدام csh البرمجة.أنا فقط ليشمل العمل في دير في localdirs أن تجعل من العمل لنفسي.

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

باستخدام sed(1) إزالة التكرارات.

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

سيؤدي هذا إلى إزالة التكرارات بعد الابتدائية ، والتي قد أو قد لا يكون ما تريد, مثلا:

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

استمتع!

هنا هو ما يمكنني استخدام - ربما شخص آخر وسوف تجد أنه من المفيد:

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

أنا دائما تعيين مسار حياتي من الصفر في .cshrc.التي بدأت مع الأساسية مسار شيئا مثل:

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

(اعتمادا على النظام).

ومن ثم القيام:

set path = ($otherPath $path)

لإضافة المزيد من الاشياء

لدي نفس الحاجة السؤال الأصلي.بناء على الإجابات السابقة ، ولقد استخدمت في كورن/POSIX/Bash:

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

كان لدي صعوبات ترجمة مباشرة في csh (csh الهروب القواعد مجنون).لقد استخدمت (كما اقترح dr_pepper):

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

هل لديك أفكار تبسيط أكثر (تقليل عدد الأنابيب) ?

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top