2008-09-25 5 views
8

Это типично, чтобы иметь что-то вроде этого в файле cshrc для задания пути:Как сохранить от дублирования переменного пути в CSH

set path = (. $otherpath $path) 

но, путь получает дублируется, когда вы источник файла cshrc несколько раз , как вы предотвращаете дублирование?

EDIT: Это один нечистый способ сделать это:

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

Связанные (хотя в основном ответы на борновские оболочки): http://stackoverflow.com/questions/273909/how-do-i-manipulate-path-elements-in-shell-scripts – dmckee 2009-12-22 14:05:28

+1

Вы должны опубликовать свой метод как отдельный ответ, не как вопрос редактирование. – 2013-01-02 19:29:48

ответ

3

вы можете использовать следующий Perl скрипт для подрезать пути дублей.


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

я надеюсь, Thats полезным.

+0

oops .. didnt понял, что я оставил все свои комментарии в нем .. все это хорошо. (BTW Еще раз спасибо Тиму) :) – ShoeLace 2012-09-07 04:34:15

0

Я всегда установить свой путь с нуля в .cshrc. То есть я начать с основным путем, что-то вроде:

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

(в зависимости от системы).

А потом сделать:

set path = ($otherPath $path) 

добавить больше материала

+0

Вы потеряете (любые обновления) системные настройки. – musiphil 2014-02-03 18:44:12

4

нормально, не в CSH, но это, как я добавляю $ HOME/бен на моем пути в Баш ...

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

приправить по вкусу ...

2

Я используют следующие (Bourne/Korn/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 оболочки, я использую:

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

Это оставляет меня с PATH, содержащим новые и другие каталоги bin спереди, плюс одну копию каждого имени каталога в главном значении пути, за исключением того, что старые и дополнительные каталоги bin удалены.

Вам придется приспособить это к оболочке C (извините, но я очень верю в истины, провозглашенные в C Shell Programming Considered Harmful). В первую очередь вам не придется возиться с сепаратором двоеточия, поэтому жизнь на самом деле проще.

2

Ну, если вы не заботитесь, в каком порядке ваши пути в, вы могли бы сделать что-то вроде:

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

Это будет сортировать ваши пути и удалить любые дополнительные пути, которые являются одинаковыми. Если у вас есть . на вашем пути вы можете удалить его с помощью grep -v и повторно добавить его в конце.

+0

Единственная проблема, с которой я вижу, это то, что она изменит порядок путей, но мне нравится то, что это однострочный. – 2008-09-30 12:52:47

2

Вот длинный один вкладыш без сортировки:.
набор путь = (echo $path | tr ' ' '\n' | perl -e 'while (<>) { print $_ unless $s{$_}++; }' | tr '\n' ' ')

1

dr_peper,

Я обычно предпочитаю придерживаться возможности создания сценариев оболочки я живу в делает его более портативный. Итак, мне понравилось ваше решение с использованием сценариев csh. Я просто расширил его, чтобы работать над каждым из местных локаций, чтобы заставить его работать для меня.

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

Im удивил никто не использовал tr ":" "\n" | grep -x techique для поиска, если данная папка уже существует в $ PATH. Любая причина не делать этого?

В 1 строке:

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

Вот функция ив сделал себе добавить несколько папок сразу $ PATH (использование «ааа: БББ: ссс» обозначение в качестве аргумента), проверки каждого из дубликатов перед добавлением:

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" 

Он имеет FOLLO преимущества крыла:

  • Никаких багизмов или какого-либо синтаксиса для конкретной оболочки. Он отлично работать с !#/bin/sh (ив протестировано с тиром)
  • Несколько папок могут быть добавлены сразу
  • Без сортировки, сохраняют порядок папок
  • предложений отлично с пробелами в именах папок
  • Один теста работает независимо от того, $ папка находится в начале, в конце, в середине или является единственной папкой в ​​$ PATH (таким образом, избегая тестирования x: *, *: x, : x:, x, так как многие из решений здесь неявно)
  • Работает (и сохраняется), если $ PATH начинается или заканчивается символом «:» или имеет в нем «::» (что означает текущую папку)
  • No awk или sed Необходимо.
  • EPA friendly;) Исходное значение IFS сохраняется, а все остальные переменные являются локальными для области функций.

Надеюсь, что это поможет!

2

Использование 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 
$ 

Наслаждайтесь!

1

Вот что я использую - возможно, кто-то будет полезен:

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

У меня такая же потребность, как оригинальный вопрос. Основываясь на ваших предыдущих ответов, я использовал в Korn/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' ' '`) 

У вас есть идеи, чтобы упростить его более (уменьшить количество труб)?

 Смежные вопросы

  • Нет связанных вопросов^_^