CSH에서 경로 변수를 복제하는 방법
-
02-07-2019 - |
문제
경로를 설정하기 위해 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. 그렇지 않은 이유가 있습니까?
1 라인으로 :
if ! $(echo "$PATH" | tr ":" "\n" | grep -qx "$dir") ; then PATH=$PATH:$dir ; fi
다음은 여러 폴더를 한 번에 $ 경로에 추가하는 기능입니다 ( "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"
다음과 같은 장점이 있습니다.
- bashism 또는 쉘 특정 구문이 없습니다. 완벽하게 실행됩니다
!#/bin/sh
(Dash로 테스트 됨) - 여러 폴더를 한 번에 추가 할 수 있습니다
- 정렬이없고 폴더 순서를 보존합니다
- 폴더 이름의 공간을 완벽하게 처리합니다
- 단일 테스트는 $ 폴더가 구거, 끝, 중간에 있거나 $ 경로의 유일한 폴더이든 상관없이 작동합니다 (따라서 테스트 x : *, *: x, :엑스:, x, 여기에 많은 솔루션이 암시 적으로하는 것처럼)
- $ 경로가 ":"또는 Has "::"로 시작되거나 끝나는 경우 작동 (및 보존) (현재 폴더 의미)
- 아니
awk
또는sed
필요합니다. - EPA 친화적 인;) 원래 IFS 값이 보존되고 다른 모든 변수는 함수 범위에 국한적입니다.
도움이되기를 바랍니다!
좋아요, ~ 아니다 CSH에서, 그러나 이것은 내가 Bash의 나의 길에 $ home/bin을 추가하는 방법입니다 ...
case $PATH in
*:$HOME/bin | *:$HOME/bin:* ) ;;
*) export PATH=$PATH:$HOME/bin
esac
맛을 맛보세요 ...
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 Shell에서는 다음을 사용합니다.
export PATH=$(clnpath /new/bin:/other/bin:$PATH /old/bin:/extra/bin)
이로 인해 전면에 새 및 기타 빈 디렉토리가 포함 된 경로와 기존 및 여분의 빈 디렉토리가 제거 된 것을 제외하고는 기본 경로 값의 각 디렉토리 이름의 사본 1 개가 있습니다.
당신은 이것을 C 쉘에 조정해야 할 것입니다 (죄송합니다 - 그러나 나는 C 쉘 프로그래밍은 유해한 것으로 간주됩니다). 주로, 당신은 결장 분리기와 함께 바이올린을 바르지 않아도되므로 실제로는 더 쉽습니다.
글쎄, 당신이 어떤 순서가 있는지 신경 쓰지 않으면 다음과 같은 일을 할 수 있습니다.
set path=(`echo $path | tr ' ' '\n' | sort | uniq | tr '\n' ' '`)
그것은 당신의 경로를 정렬하고 동일한 경로를 제거합니다. 당신이 가지고 있다면 . 당신의 경로에서, 당신은 grep -v로 그것을 제거하고 끝에 다시 접수 할 수 있습니다.
정렬하지 않은 긴 1 라이너가 있습니다.
set path = ( echo $path | tr ' ' '\n' | perl -e 'while (<>) { print $_ unless $s{$_}++; }' | tr '\n' ' '
)
dr_peper,
나는 보통 내가 살고있는 쉘의 스크립팅 기능을 고수하는 것을 선호합니다. 더 휴대용으로 만듭니다. CSH 스크립팅을 사용하여 솔루션이 마음에 들었습니다. 나는 방금 현지 디르의 DIR PER 작업을 위해 연장하여 직접 작동하도록 확장했습니다.
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)
더 많은 물건을 추가합니다
원래 질문과 같은 필요가 있습니다. 이전 답변을 바탕으로 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' ' '`)
더 단순화하는 아이디어가 있습니까 (파이프 수를 줄이십시오)?