2008-09-25 68 views
8

這是典型的在你的.cshrc文件是這樣設置的路徑:如何保持在CSH複製路徑變量

set path = (. $otherpath $path) 

,但該路徑被當你多次源的.cshrc文件複製,你如何防止重複?

編輯:這是做這件事的一個不潔的方式:

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

相關(雖然主要是Bourne shell的答案):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; 
    } 
} 

我希望這就是有用的。

+0

哎呀..沒有意識到我已經把所有的評論都留在了它裏面..它的一切都很好。 (順便說一句,再次感謝蒂姆):) – 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

OK,在csh,但是這是我的$ HOME/bin中追加到我在bash路徑...

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

季節的味道...

2

我已經使用以下(伯恩/科恩/ 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) 

這使我在前面包含新的和其他bin目錄的PATH,加上主路徑值中每個目錄名稱的一個副本,除了舊的和額外的bin目錄已刪除bin。你將不得不適應這個C shell(對不起 - 但我非常相信在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

我很驚訝沒有人使用tr ":" "\n" | grep -x技術來搜索給定的文件夾是否已經存在於$ 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或任何shell特定的語法。它與!#/bin/sh(IVE與前圍測試)
  • 多個文件夾可以一次
  • 沒有排序被添加,在文件夾名稱空間保存文件夾以便
  • 優惠完美
  • 單個測試工作,不管是否完美運行$文件夾位於開始,結束,中間或是$ PATH中的唯一文件夾(因此避免測試x:*,*:x,:x:,x,因爲這裏隱含的解決方案很多)
  • 如果$ PATH以「:」開始或結束,或者其中包含「::」(表示當前文件夾),則工作(並保留)
  • 否需要awksed
  • 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 /猛砸已經使用:

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' ' '`) 

您是否有更多簡化它的想法(減少管道數量)?