Как избежать дублирования переменной пути в csh
Это типично иметь что-то подобное в вашем файле cshrc для установки пути:
set path = ( . $otherpath $path )
но путь дублируется, когда вы несколько раз отправляете файл cshrc, как вы предотвращаете дублирование?
EDIT: Это один нечистый способ сделать это:
- Где хранить скрипты bash, которые все пользователи могут выполнять на Debian?
- WPF C # Путь: как получить из строки с данными пути в геометрию в коде (не в XAML)
- Java: как импортировать файл jar из командной строки
- Как изменить папку запуска Jupyter
- Как добавить собственную библиотеку в «java.library.path» с запуском Eclipse (вместо того, чтобы переопределять его)
set localpaths = ( . $otherpaths ) echo ${path} | egrep -i "$localpaths" >& /dev/null if ($status != 0) then set path = ( . $otherpaths $path ) endif
- Проверьте правильность пути
- Eclipse - нет Java (JRE) / (JDK) ... нет виртуальной машины
- Список всех файлов, соответствующих шаблону полного пути в R
- Переменная окружения Deleted Path, как восстановить?
- Как я могу найти фактический путь, найденный BFS?
- Как получить рабочий путь приложения wcf?
- Как получить путь к запущенному файлу JAR?
- Как найти путь к текущему проекту в Java, Eclipse?
вы можете использовать следующий скрипт Perl для сокращения путей дублирования.
#!/usr/bin/perl # # ^^ ensure this is pointing to the correct location. # # Title: SLimPath # Author: David "Shoe Lace" Pyke # : 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 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; } }
Надеюсь, это полезно.
Im удивил, что никто не использовал tr ":" "\n" | grep -x
tr ":" "\n" | grep -x
techique для поиска, если данная папка уже существует в $ PATH. Любая причина не делать этого?
В 1 строке:
if ! $(echo "$PATH" | tr ":" "\n" | grep -qx "$dir") ; then PATH=$PATH:$dir ; fi
Вот функция ive заставила себя добавить несколько папок сразу в $ 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
(проверено с тире) - Несколько папок могут быть добавлены сразу
- Нет сортировки, сохраняет порядок папок
- Идеально подходит для пробелов в именах папок
- Один тест работает независимо от того, находится ли папка $ в начале, конце, середине или является единственной папкой в $ PATH (таким образом, избегая тестирования x: *, *: x,: x:, x, так как многие из решений здесь неявно делать)
- Работает (и сохраняет), если $ PATH начинается или заканчивается на «:», или имеет в нем «::» (что означает текущую папку)
- Нет необходимости в
awk
илиsed
. - EPA friendly;) Исходное значение IFS сохраняется, а все остальные переменные являются локальными для области функций.
Надеюсь, это поможет!
ok, а не в csh, но это то, как я добавляю $ HOME / bin к моему пути в bash …
case $PATH in *:$HOME/bin | *:$HOME/bin:* ) ;; *) export PATH=$PATH:$HOME/bin esac
сезон по вкусу …
Я использую следующий (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 удалили bin.
Вам придется адаптировать это к оболочке C (извините, но я очень верю в истины, провозглашенные в C Shell Programming, учитывая вредность ). В первую очередь вам не придется возиться с сепаратором двоеточия, поэтому жизнь на самом деле проще.
Ну, если вам все равно, какой порядок у вас есть, вы можете сделать что-то вроде:
set path=(`echo $path | tr ' ' '\n' | sort | uniq | tr '\n' ' '`)
Это сортирует ваши пути и удаляет любые дополнительные пути, которые являются одинаковыми. Если у вас есть . на вашем пути вы можете удалить его с помощью grep -v и повторно добавить его в конце.
Вот длинный однострочный без сортировки:
set path = ( echo $path | tr ' ' '\n' | perl -e 'while (<>) { print $_ unless $s{$_}++; }' | tr '\n' ' '
)
dr_peper,
Обычно я предпочитаю использовать возможности сценариев оболочки, в которой я живу. Делает ее более переносимой. Итак, мне понравилось ваше решение с использованием сценариев csh. Я просто расширил его, чтобы работать над каждым из местных локаций, чтобы заставить его работать для меня.
foreach dir ($ localdirs) echo $ {путь} | egrep -i "$ dir"> & / dev / null if ($ status! = 0), тогда set path = ($ dir $ path) ENDIF конец
Использование 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; ta; 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 # JP 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 escape rules are insane). Я использовал (как было предложено dr_pepper):
set path = ( `echo $otherpath $path | tr ' ' '\n' | perl -ne 'print $_ unless $h{$_}++' | tr '\n' ' '`)
У вас есть идеи, чтобы упростить его (уменьшить количество труб)?