9

パスを設定するために、cshrcファイルに次のようなものを含めるのが一般的です。

set path = ( . $otherpath $path )

しかし、cshrcファイルを複数回ソースすると、パスが重複します。重複を防ぐにはどうすればよいですか?

編集:これはそれを行うための1つの汚れた方法です:

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

12 に答える 12

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"

次の利点があります。

  • バシズムやシェル固有の構文はありません。完全に実行されます!#/bin/sh(ダッシュでテスト済み)
  • 一度に複数のフォルダを追加できます
  • 並べ替えなし、フォルダの順序を保持
  • フォルダ名のスペースを完全に処理
  • $folder が最初、最後、中間、または $PATH 内の唯一のフォルダーであるかどうかに関係なく、単一のテストが機能します (したがって、x:*、*:x、:x:、x のテストを回避します。ここでのソリューションの多くは暗黙的に行われます)行う)
  • $PATH が ":" で開始または終了するか、"::" が含まれている場合 (現在のフォルダーを意味する) に動作 (および保持) します。
  • いいえawk、またはsed必要です。
  • EPA フレンドリー ;) 元の IFS 値が保持され、他のすべての変数は関数スコープに対してローカルです。

それが役立つことを願っています!

于 2011-02-19T05:02:00.190 に答える
4

わかりました、cshではありませんが、これは $HOME/bin を bash のパスに追加する方法です...

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

味わう季節…

于 2008-09-25T21:07:57.783 に答える
3

次の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;
    }
}

お役に立てば幸いです。

于 2008-09-25T20:28:48.687 に答える
2

並べ替えのない長いワンライナーは次のとおり
です。setpath=(echo $path | tr ' ' '\n' | perl -e 'while (<>) { print $_ unless $s{$_}++; }' | tr '\n' ' '

于 2008-09-30T20:38:55.787 に答える
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
$

楽しみ!

于 2012-01-28T09:36:53.537 に答える
2

パスの順序を気にしない場合は、次のようにすることができます。

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

これにより、パスが並べ替えられ、同じ余分なパスが削除されます。あなたが持っている場合 。パスで grep -v を使用して削除し、最後に再度追加することをお勧めします。

于 2008-09-29T13:46:03.590 に答える
2

dr_peper、

私は通常、自分が住んでいるシェルのスクリプト機能に固執することを好みます。移植性が高くなります。したがって、csh スクリプトを使用したソリューションが気に入りました。localdirs のディレクトリごとに機能するように拡張して、自分で機能させるようにしました。

foreach ディレクトリ ( $localdirs )
    エコー ${パス} | egrep -i "$dir" >& /dev/null
    もし ($ステータス != 0) なら
        パスを設定 = ( $dir $path )
    終了
終わり
于 2009-11-19T05:26:37.410 に答える
2

私は 10 年間、次の (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)

これにより、先頭に新しいおよび他の bin ディレクトリを含む PATH が残り、メインパス値に各ディレクトリ名の 1 つのコピーが含まれます。ただし、古いおよび余分な bin ディレクトリは bin が削除されています。

これを C シェルに適応させる必要があります (申し訳ありませんが、私はC Shell Programming Considered Harmfulで述べられている真実を大いに信じています)。主に、コロン区切り記号をいじる必要がないので、実際には作業が楽になります。

于 2008-09-26T06:03:54.607 に答える
0

私は常に .cshrc で最初からパスを設定します。つまり、次のような基本的なパスから始めます。

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

(システムによって異なります)。

そして、次のようにします。

set path = ($otherPath $path)

より多くのものを追加するには

于 2008-09-25T20:20:54.790 に答える
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' ' '`)

もっと単純化する(パイプの数を減らす)アイデアはありますか?

于 2015-02-18T13:04:23.553 に答える