디렉토리가 없으면 $ PATH에 디렉토리를 추가하십시오.


126

디렉토리가 아직없는 경우에만 $ PATH에 디렉토리를 추가하기 위해 bash 함수를 작성한 사람이 있습니까?

나는 일반적으로 다음과 같은 것을 사용하여 PATH에 추가합니다.

export PATH=/usr/local/mysql/bin:$PATH

.bash_profile에서 PATH를 구성하면 현재 세션이 로그인 세션이 아닌 한 읽지 않습니다. 항상 그렇지는 않습니다. .bashrc에 PATH를 구성하면 각 하위 쉘과 함께 실행됩니다. 따라서 터미널 창을 시작한 다음 화면을 실행 한 다음 셸 스크립트를 실행하면 다음과 같은 결과가 나타납니다.

$ echo $PATH
/usr/local/mysql/bin:/usr/local/mysql/bin:/usr/local/mysql/bin:....

add_to_path()디렉토리가없는 경우에만 디렉토리를 추가 하는 bash 함수를 작성하려고 합니다. 그러나 아무도 이미 그런 것을 쓰거나 발견했다면, 나는 그것에 시간을 소비하지 않을 것입니다.


도움이되는 일부 인프라에 대해서는 stackoverflow.com/questions/273909/… 를 참조하십시오 .
dmckee


문제가 "아직 추가되지 않은 경우에만 추가"로 프레임을 구성하면 삽입 된 항목이 시작 부분에 중요하지만 시작되지 않는 날이 올 때 무례하게 놀라게 될 것입니다. 더 나은 방법은 요소를 삽입 한 다음 복제본을 제거하는 것입니다. 따라서 새 항목이 이미 있으면 효과적으로 시작 부분으로 이동합니다.
Don Hatch

답변:


125

내 .bashrc에서 :

pathadd() {
    if [ -d "$1" ] && [[ ":$PATH:" != *":$1:"* ]]; then
        PATH="${PATH:+"$PATH:"}$1"
    fi
}

PATH는 이미 익스포트 된 것으로 표시되어 있으므로 익스포트 할 필요가 없습니다. 디렉토리를 추가하기 전에 디렉토리가 존재하고 디렉토리인지 여부를 확인합니다.

또한 경로 끝에 새 디렉토리가 추가됩니다. 처음에 넣으 PATH="$1${PATH:+":$PATH"}"려면 위의 PATH=줄 대신을 사용 하십시오 .


26
나는 걱정한다.
Dennis Williamson

4
@Neil : 그것은 ":$PATH:"단지 대신에 비교되기 때문에 작동합니다"$PATH"
Gordon Davisson

3
@ GordonDavisson : 사과합니다, 내 테스트가 잘못되었고 당신이 맞습니다.
Neil

2
@GordonDavisson 중괄호 안의 내용은 무엇입니까? 난 " ${PATH:+"$PATH:"}$ 1"을
풀지

5
@ Mark0978 : bukzor가 지적한 문제를 해결하기 위해 내가 한 일입니다. ${variable:+value}의미 variable는 정의되어 있고 비어 있지 않은 값이 있는지 여부를 확인 하고 평가 결과를 제공함을 의미합니다 value. 기본적으로 PATH가 비어 있지 않으면 시작으로 설정합니다 "$PATH:$1". 비어 있으면 그냥 설정합니다 "$1"(콜론이 없음에 유의하십시오).
Gordon Davisson

19

Gordon Davisson의 답변을 확장하여 여러 가지 주장을 지원합니다.

pathappend() {
  for ARG in "$@"
  do
    if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
        PATH="${PATH:+"$PATH:"}$ARG"
    fi
  done
}

그래서 당신은 path1을 추가 할 수 있습니다 path1 path2 path3 ...

선행하기 위해

pathprepend() {
  for ((i=$#; i>0; i--)); 
  do
    ARG=${!i}
    if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
        PATH="$ARG${PATH:+":$PATH"}"
    fi
  done
}

pathappend와 유사하게 할 수 있습니다

pathprepend path1 path2 path3 ...


3
대단해! 한 가지 작은 변화를주었습니다. 'pathprepend'함수의 경우 인수를 역으로 읽는 것이 편리하므로 예를 들어으로 pathprepend P1 P2 P3끝날 수 있습니다 PATH=P1:P2:P3. 이 동작을 얻으려면, 변경 for ARG in "$@" dofor ((i=$#; i>0; i--)); do ARG=${!i}
이스마엘

감사합니다 @ishmael, 좋은 제안, 나는 답변을 편집했습니다. 귀하의 의견이 2 세 이상인 것을 알고 있지만 그 이후로 돌아 오지 않았습니다. 스택 교환 이메일을받은 편지함에 도착시키는 방법을 알아야합니다!
기 illa 페로-아카 람바 ult 트

14

다음은 이 질문에 대한 답변 에서 Doug Harris의 기능 구조와 결합 된 것입니다. Bash 정규식을 사용합니다.

add_to_path ()
{
    if [[ "$PATH" =~ (^|:)"${1}"(:|$) ]]
    then
        return 0
    fi
    export PATH=${1}:$PATH
}

이것은 $1대신 대신 사용하여 작동했습니다${1}
Andrei

@Andrei : 예,이 경우에는 중괄호가 필요하지 않습니다. 왜 그것들을 포함했는지 잘 모르겠습니다.
Dennis Williamson

10

이것을 선택한 답변에 대한 주석에 넣으십시오. 그러나 주석은 PRE 형식을 지원하지 않는 것이므로 여기에 답변을 추가하십시오.

@ gordon-davisson 나는 불필요한 인용 및 연결에 대한 열렬한 팬이 아닙니다. bash 버전> = 3을 사용한다고 가정하면 대신 bash의 내장 정규식을 사용하고 다음을 수행 할 수 있습니다.

pathadd() {
    if [ -d "$1" ] && [[ ! $PATH =~ (^|:)$1(:|$) ]]; then
        PATH+=:$1
    fi
}

디렉토리 또는 PATH에 공백이있는 경우를 올바르게 처리합니다. bash의 내장 정규식 엔진이 속도가 느려서 버전이 수행하는 문자열 연결 및 보간보다 효율성이 떨어질 수 있는지에 대한 질문이 있지만 어떻게 든 나에게 더 미학적으로 깨끗하다고 ​​느낍니다.


1
주석 formatting using the backtick만 지원 하지만 적절한 단락 제어 기능은 없습니다.
보트 코더

이것은 끝에 추가를 넣습니다. 기존 위치를 무시하기 위해 처음에 추가하는 것이 종종 바람직합니다.
Dennis Williamson

@DennisWilliamson 기본 동작으로 권장하지는 않지만 공정한 요점입니다. 접두사 변경 방법을 알아내는 것은 어렵지 않습니다.
Christopher Smith

@ChristopherSmith-re : null이 아닌 unnecessary quoting것을 미리 알 수 있습니다 $PATH. "$PATH"PATH가 null인지 아닌지를 확인합니다. 마찬가지로 $1명령 파서를 혼동시킬 수있는 문자가 포함 된 경우 . 정규 표현식을 따옴표로 묶으면 해당 단어를 "(^|:)$1(:|$)"막을 수 있습니다.
Jesse Chisholm

@JesseChisholm : 사실, 나는 크리스토퍼의 포인트는 규칙과 다른 점이다 생각 [[하고 ]]. 나는 그 실패를 발생하지 않는 한 가능하게 인용해야 할 수있는 모든 것을 인용하는 것을 선호하지만, 나는 그가 바로 생각, 그것은되지 않습니다 정말 인용 필요한 주변 $PATH. 반면에, 당신이 옳은 것 같습니다 $1.
Scott

7
idempotent_path_prepend ()
{
    PATH=${PATH//":$1"/} #delete any instances in the middle or at the end
    PATH=${PATH//"$1:"/} #delete any instances at the beginning
    export PATH="$1:$PATH" #prepend to beginning
}

$ PATH의 시작 부분에 $ HOME / bin이 정확히 한 번만 나타나고 다른 곳에서는 나타나지 않으면 대체물을 사용하지 마십시오.


고마워, 그것은 훌륭한 우아한 해결책이지만, 작동시키기 위해서는 PATH=${PATH/"...보다는 오히려 해야한다는 것을 알았습니다 PATH=${PATH//".
Mark Booth

이중 슬래시 양식은 여러 개의 일치 항목과 일치해야합니다. 단일 슬래시는 첫 번째 슬래시와 만 일치합니다 (bash 매뉴얼 페이지에서 "패턴 대체"검색). 왜 작동하지 않는지 모르겠습니다.
andybuckley

이것은 $1유일한 항목 (콜론 없음) 인 비정상적인 경우에 실패합니다 . 항목이 두 배가됩니다.
Dennis Williamson

또한 PeterS6g가 지적한 것처럼 너무 적극적으로 삭제 합니다.
Dennis Williamson

6

다음은 중복 전체를 제거 할 수있는 추가 이점이있는 대체 솔루션입니다.

function pathadd {
    PATH=:$PATH
    PATH=$1${PATH//:$1/}
}

이 함수에 대한 단일 인수는 PATH 앞에 추가되고 동일한 문자열의 첫 번째 인스턴스는 기존 경로에서 제거됩니다. 다시 말해, 디렉토리가 이미 경로에 존재하는 경우 복제본으로 추가되지 않고 앞쪽으로 승격됩니다.

이 함수는 경로 앞에 콜론을 추가하여 모든 항목 앞에 콜론이 있는지 확인한 다음 해당 항목이 제거 된 기존 경로 앞에 새 항목을 추가합니다. 마지막 부분은 bash ${var//pattern/sub}표기법을 사용하여 수행 됩니다. 자세한 내용 은 bash 매뉴얼 을 참조하십시오.


좋은 생각; 결함이있는 구현. /home/robert당신 PATH과 당신 이 이미 있다면 어떻게되는지 고려하십시오 pathadd /home/rob.
Scott

5

여기 내 것이 있습니다 (오래 전 실험실의 관리자 인 Oscar가 그에게 모든 신용을 썼습니다), 그것은 내 bashrc에서 오랫동안 사용되었습니다. 새 디렉토리를 원하는대로 추가하거나 추가 할 수있는 이점이 있습니다.

pathmunge () {
        if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then
           if [ "$2" = "after" ] ; then
              PATH=$PATH:$1
           else
              PATH=$1:$PATH
           fi
        fi
}

용법:

$ echo $PATH
/bin/:/usr/local/bin/:/usr/bin
$ pathmunge /bin/
$ echo $PATH
/bin/:/usr/local/bin/:/usr/bin
$ pathmunge /sbin/ after
$ echo $PATH
/bin/:/usr/local/bin/:/usr/bin:/sbin/

5

접두사로 @Russell의 솔루션이 마음에 들지만 작은 버그가 있습니다. "/ bin"과 같은 경로를 "/ sbin : / usr / bin : / var / usr / bin : / usr / local 경로 앞에 추가하려고하면 / bin : / usr / sbin ""/ bin : "을 3 번 대체합니다 (실제로 일치하지 않는 경우). @ gordon-davisson의 추가 솔루션과 수정 사항을 결합하면 다음과 같이됩니다.

path_prepend() {
    if [ -d "$1" ]; then
        PATH=${PATH//":$1:"/:} #delete all instances in the middle
        PATH=${PATH/%":$1"/} #delete any instance at the end
        PATH=${PATH/#"$1:"/} #delete any instance at the beginning
        PATH="$1${PATH:+":$PATH"}" #prepend $1 or if $PATH is empty set to $1
    fi
}

4

아래의 이와 같은 간단한 별칭이 트릭을 수행해야합니다.

alias checkInPath="echo $PATH | tr ':' '\n' | grep -x -c "

그것은 : 문자의 경로를 나누고 각 구성 요소를 전달하는 인수와 비교하는 것입니다. grep은 완전한 행 일치를 확인하고 카운트를 인쇄합니다.

샘플 사용법 :

$ checkInPath "/usr/local"
1
$ checkInPath "/usr/local/sbin"
1
$ checkInPath "/usr/local/sbin2"
0
$ checkInPath "/usr/local/" > /dev/null && echo "Yes" || echo "No"
No
$ checkInPath "/usr/local/bin" > /dev/null && echo "Yes" || echo "No"
Yes
$ checkInPath "/usr/local/sbin" > /dev/null && echo "Yes" || echo "No"
Yes
$ checkInPath "/usr/local/sbin2" > /dev/null && echo "Yes" || echo "No"
No

echo 명령을 addToPath 또는 유사한 별명 / 함수로 바꾸십시오.


"grep -x"를 사용하는 것은 아마도 내 bash 함수에 넣은 루프보다 빠를 것입니다.
Doug Harris


2

내가 채찍질 한 내용은 다음과 같습니다.

add_to_path ()
{
    path_list=`echo $PATH | tr ':' ' '`
    new_dir=$1
    for d in $path_list
    do
        if [ $d == $new_dir ]
        then
            return 0
        fi
    done
    export PATH=$new_dir:$PATH
}

이제 .bashrc에는 다음이 있습니다.

add_to_path /usr/local/mysql/bin

원본이 공백이있는 디렉토리를 처리하지 않는 방법에 대한 의견에 따라 업데이트 된 버전 ( 이 질문 으로 인해을 사용하도록 지정했습니다 IFS) :

add_to_path ()
{
    new_dir=$1
    local IFS=:
    for d in $PATH
    do
        if [[ "$d" == "$new_dir" ]]
        then
            return 0
        fi
    done
    export PATH=$new_dir:$PATH
}

1
디렉토리 이름이 이미있는 경우 실패 할 수 PATH공백을 포함 *, ?또는 [... ].
Scott

좋은 지적은 ...하지만 나는 구식 리눅스 사람이고 그 안에 공백이있는 경로를 사용하지 않을 것입니다 :-)
Doug Harris

이름에 공백이있는 것을 만들지 않아서 좋습니다. 코드가 존재할 때 처리 할 수없는 코드를 작성하는 것은 부끄러운 일입니다. 그리고“오래된 Linux 사람”이되는 것과 관련이 있습니까? Windoze는 수도 대중화 아이디어를 (감사합니다, Documents and Settings하고 Program Files)하지만, 유닉스있다 지원 Windoze 존재 전부터 공백을 포함하는 경로 이름을.
Scott

2

아무도 아직 이것을 언급하지 않은 것에 약간 놀랐지 만 readlink -f상대 경로를 절대 경로로 변환하고 PATH에 추가하는 데 사용할 수 있습니다 .

예를 들어 Guillaume Perrault-Archambault의 답변을 개선하기 위해

pathappend() {
  for ARG in "$@"
  do
    if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
        PATH="${PATH:+"$PATH:"}$ARG"
    fi
  done
}

된다

pathappend() {
    for ARG in "$@"
    do
        if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]
        then
            if ARGA=$(readlink -f "$ARG")               #notice me
            then
                if [ -d "$ARGA" ] && [[ ":$PATH:" != *":$ARGA:"* ]]
                then
                    PATH="${PATH:+"$PATH:"}$ARGA"
                fi
            else
                PATH="${PATH:+"$PATH:"}$ARG"
            fi
        fi
    done
}

1. 기본 —이 기능은 무엇입니까?

readlink -f명령은 (다른 것들 중에서) 상대 경로를 절대 경로로 변환합니다. 이것은 당신이 같은 것을 할 수 있습니다

$ cd / path / to / my / bin / dir
$ pathappend .
$ echo "$ PATH"
<your_old_path> : / path / to / my / bin / dir

2. 왜 우리는 두 번 PATH에 있는지 테스트합니까?

위의 예를 고려하십시오. 사용자가 말한다면 으로부터 두 번째는 디렉토리 됩니다 . 물론에 없습니다 . 그런데 로 설정한다 (절대 경로 등가 ) 이미 . 따라서 우리 는 두 번째로 추가하지 않아야 합니다 .pathappend ./path/to/my/bin/dirARG..PATHARGA/path/to/my/bin/dir.PATH/path/to/my/bin/dirPATH

아마도 더 중요한 것은 readlink그 이름에서 알 수 있듯이 기본 링크의 목적은 심볼릭 링크를보고 포함 된 경로 이름을 읽는 것입니다 (즉, 가리킴). 예를 들면 다음과 같습니다.

$ ls -ld /usr/lib/perl/5.14
-rwxrwxrwx  1   root   root    Sep  3  2015 /usr/lib/perl/5.14 -> 5.14.2
$ readlink /usr/lib/perl/5.14
5.14.2
$ readlink -f /usr/lib/perl/5.14
/usr/lib/perl/5.14.2

자,이라고 말하고 pathappend /usr/lib/perl/5.14이미 /usr/lib/perl/5.14PATH에 있다면, 괜찮습니다. 그대로 그대로 둘 수 있습니다. 하지만, /usr/lib/perl/5.14당신의 PATH에없는, 우리는 전화를 readlink얻을 ARGA=을 /usr/lib/perl/5.14.2하고 우리는 추가 하는 것이PATH. 그러나 잠깐 - 당신이 경우 이미 말했다 pathappend /usr/lib/perl/5.14, 당신은 이미 /usr/lib/perl/5.14.2, 다시, 우리가에 추가 피하기 위해 그것을 위해 확인해야 PATH에, 그리고 PATH두 번째.

3. 거래는 if ARGA=$(readlink -f "$ARG")무엇입니까?

확실하지 않은 경우이 줄은 readlink성공 여부를 테스트합니다 . 이것은 좋은 방어 적 프로그래밍 연습입니다. 우리가 명령의 출력 사용하고자하는 경우  m를의 일부 명령  N (여기서 m  <  N )는 명령 여부를 확인하는 신중한  m가 어떤 방법으로 그 실패하고 처리합니다. 나는 그것이 readlink실패 할 것이라고 생각하지 않는다. 그러나 OS X 와 다른 곳 에서 임의의 파일의 절대 경로를 검색하는 방법에서 논의 된 바와 같이 readlink, GNU 발명이다. POSIX에는 지정되어 있지 않으므로 Mac OS, Solaris 및 기타 비 Linux 유닉스에서의 가용성에 의문의 여지가 있습니다. (사실, 난 그냥 읽고 코멘트 "라고readlink -f맥 OS X 10.11.6에 제대로 작동하지 않지만, realpath상자 밖으로 작동합니다. "그래서, 당신이하지 않는 시스템에 있다면 readlink, 또는 경우 readlink -f작동하지 않습니다, 당신이 이것을 수정할 수 있습니다 스크립트를 사용할 수 있습니다 realpath.) 안전망을 설치하여 코드를 좀 더 이식성있게 만듭니다.

물론, 시스템이 없거나 readlink(또는  realpath) 없는 시스템 에서는 할 수 없습니다 .pathappend .

두 번째 -d테스트 ( [ -d "$ARGA" ])는 실제로 불필요합니다. $ARG디렉토리가 있고 readlink성공하지만  $ARGA디렉토리가 아닌 시나리오 는 생각할 수 없습니다 . 방금 첫 번째 if문장을 복사하여 붙여 넣어 세 번째 문장을 작성하고  -d테스트를 게으름에서 벗어났습니다.

4. 다른 의견?

네. 여기에있는 다른 많은 답변들과 마찬가지로,이 방법은 각 인수가 디렉토리인지 여부를 테스트하고, 디렉토리가 있으면 처리하며, 그렇지 않으면 무시합니다. 사용중인 경우 (또는하지 않을 수 있습니다) 적합 할 수 pathappend "만 ."(같은 파일 .bash_profile.bashrc) 및 기타 스크립트. 그러나 위의 답변에서 볼 수 있듯이 대화식으로 사용하는 것이 가능합니다. 당신이 할 경우 당신은 매우 당황 할 것이다

$ pathappend /usr/local/nysql/bin
$ mysql
-bash: mysql: command not found

내가 아니라 명령 nysql 에서 내가 말한 것을 알았습니까 ? 그리고 그것은 아무 말도하지 않았습니다. 잘못된 인수를 자동으로 무시 했습니까?pathappendmysqlpathappend

위에서 말했듯이 오류를 처리하는 것이 좋습니다. 예를 들면 다음과 같습니다.

pathappend() {
    for ARG in "$@"
    do
        if [ -d "$ARG" ]
        then
            if [[ ":$PATH:" != *":$ARG:"* ]]
            then
                if ARGA=$(readlink -f "$ARG")           #notice me
                then
                    if [[ ":$PATH:" != *":$ARGA:"* ]]
                    then
                        PATH="${PATH:+"$PATH:"}$ARGA"
                    fi
                else
                    PATH="${PATH:+"$PATH:"}$ARG"
                fi
            fi
        else
            printf "Error: %s is not a directory.\n" "$ARG" >&2
        fi
    done
}

(1) 따옴표를 추가해야합니다 readlink -f "$ARG". (2) 왜 이런 일이 일어날 지 모르겠지만 (특히 -d "$ARG"테스트에 성공한 후 ) readlink실패 했는지 테스트하고 싶을 수도 있습니다 . (3) readlink심볼릭 링크 이름을“실제 파일 이름”에 매핑하는의 주요 기능을 간과하고있는 것 같습니다 . (예를 들어) /bin가에 대한 심볼릭 링크 인 경우을 /bin64반복해서 호출하면 pathappend /binPATH가 발생할 수 있습니다 …:/bin64:/bin64:/bin64:/bin64:…. 의 새 값 $ARG이 이미 있는지 확인해야 할 수도 있습니다 PATH.
Scott

(1) 좋은 관찰, 나는 그것을 고쳤다. (2) 어떤 경우에 readlink가 실패합니까? 경로가 정확하고 올바른 위치를 참조한다고 가정합니다. (3) readlink의 주요 기능이 무엇인지 잘 모르겠습니다. 유닉스 파일 시스템의 대부분의 경로는 두 가지 유형의 링크, 기호 링크 및 하드 링크로 나눌 수 있다고 생각합니다. 중복 경로 항목은 옳지 만 내 대답의 목적은 그것을 추가하지 않는 것입니다 (다른 답변에서 이미 언급했음을 알았으므로). 내가 또 다른 답변을 추가하는 유일한 이유는 내가 이미 기여하지 않은 것으로 생각한 것에 기여하는 것입니다.
qwertyzw

(2) 최소한 명령의 이름이 목적에 따라 암시 / 힌트 된 경우 readlink의 'link'는 하드 링크 또는 소프트 링크를 나타낼 수 있습니다. 그러나 당신은 맞습니다 : man readlink는 'readlink-해결 된 심볼릭 링크 또는 표준 파일 이름 인쇄'라고 말합니다 .. 제 예에서는 표준 파일 이름으로 간주 될 수 있다고 생각합니다. 옳은?
qwertyzw

(1) 심볼릭 링크를 이해하는 사람들에게 readlink'이름은 그 링크 의 목적을 분명히 나타냅니다. 심볼릭 링크를보고 포함 된 경로 이름을 읽습니다 (예 : 포인트). (2) 글쎄, 나는readlink실패 할지 몰랐다 . 나는 스크립트 나 함수가 여러 명령을 포함하고 명령하면되는 일반 지점을 만들고 있었다  n을 격변 실패 보증 (또는 전혀 이해가되지 않습니다) 명령의 경우  m은 실패 (여기서 m는  <  N ), 그것은 신중 좋은 방법입니다 검사 명령 여부 m은 실패하고 어떤 방법으로 그 처리 -, ... (계속) 최소한
스콧

(계속) ... 진단으로 스크립트 / 기능을 중단합니다. readlink(a) testand 와의 호출 사이에서 (다른 프로세스에 의해) 디렉토리 이름이 바뀌거나 삭제 readlink되거나 (b) /usr/bin/readlink삭제되거나 손상된 경우 가설 이 실패 할 수 있습니다. (3) 당신은 내 요점을 놓치고있는 것 같습니다. 나는 당신이 다른 답변을 복제하도록 권장하지 않습니다. 나는 ARG(명령 줄에서) 원본 이 이미에 있는지 확인 PATH하지만 새로운 (에 대한 출력 )에 대한 확인을 반복 하지 않으면 대답이 불완전하고 잘못되었습니다. … (계속)ARGreadlink
Scott

1
function __path_add(){  
if [ -d "$1" ] ; then  
    local D=":${PATH}:";   
    [ "${D/:$1:/:}" == "$D" ] && PATH="$PATH:$1";  
    PATH="${PATH/#:/}";  
    export PATH="${PATH/%:/}";  
fi  
}  

1

이 방법은 잘 작동합니다.

if [[ ":$PATH:" != *":/new-directory:"* ]]; then PATH=${PATH}:/new-directory; fi

0

내 버전은 빈 경로와 여기에 게시 된 경로보다 유효한 경로 및 디렉토리를 주장하는 데 덜주의를 기울이지 만 prepend / append / clean / unique-ify / etc 등의 대규모 컬렉션을 찾습니다. 경로 조작에 유용한 쉘 함수. 전체 많이, 현재 상태로, 현재 위치 : http://pastebin.com/xS9sgQsX (피드백과 개선을 매우 환영!)


0

펄 원 라이너를 사용할 수 있습니다 :

appendPaths() { # append a group of paths together, leaving out redundancies
    # use as: export PATH="$(appendPaths "$PATH" "dir1" "dir2")
    # start at the end:
    #  - join all arguments with :,
    #  - split the result on :,
    #  - pick out non-empty elements which haven't been seen and which are directories,
    #  - join with :,
    #  - print
    perl -le 'print join ":", grep /\w/ && !$seen{$_}++ && -d $_, split ":", join ":", @ARGV;' "$@"
}

여기 bash에 있습니다.

addToPath() { 
    # inspired by Gordon Davisson, http://superuser.com/a/39995/208059
    # call as: addToPath dir1 dir2
    while (( "$#" > 0 )); do
    echo "Adding $1 to PATH."
    if [[ ! -d "$1" ]]; then
        echo "$1 is not a directory.";
    elif [[ ":$PATH:" == *":$1:"* ]]; then
        echo "$1 is already in the path."
    else
            export PATH="${PATH:+"$PATH:"}$1" # ${x:-defaultIfEmpty} ${x:+valueIfNotEmpty}
    fi
    shift
    done
}

0

제공되지 않은 경우 현재 디렉토리를 사용 하도록 Gordon Davisson의 답변 을 약간 수정했습니다 . 따라서 paddPATH에 추가하려는 디렉토리에서 수행 할 수 있습니다 .

padd() {
  current=`pwd`
  p=${1:-$current}
  if [ -d "$p" ] && [[ ":$PATH:" != *":$p:"* ]]; then
      PATH="$p:$PATH"
  fi
}

0

맞춤 변수가 설정되어 있는지 확인하고, 그렇지 않으면 설정 한 다음 새 항목을 추가 할 수 있습니다.

if [ "$MYPATHS" != "true" ]; then
    export MYPATHS="true"
    export PATH="$PATH:$HOME/bin:"

    # java stuff
    export JAVA_HOME="$(/usr/libexec/java_home)"
    export M2_HOME="$HOME/Applications/apache-maven-3.3.9"
    export PATH="$JAVA_HOME/bin:$M2_HOME/bin:$PATH"

    # etc...
fi

물론 이러한 항목은와 같은 다른 스크립트에 의해 추가 된 경우에도 복제 될 수 있습니다 /etc/profile.


0

이 스크립트를 사용하면 다음 끝에 추가 할 수 있습니다 $PATH.

PATH=path2; add_to_PATH after path1 path2:path3
echo $PATH
path2:path1:path3

또는 시작 부분에 추가하십시오 $PATH.

PATH=path2; add_to_PATH before path1 path2:path3
echo $PATH
path1:path3:path2

# Add directories to $PATH iff they're not already there
# Append directories to $PATH by default
# Based on https://unix.stackexchange.com/a/4973/143394
# and https://unix.stackexchange.com/a/217629/143394
add_to_PATH () {
  local prepend  # Prepend to path if set
  local prefix   # Temporary prepended path
  local IFS      # Avoid restoring for added laziness

  case $1 in
    after)  shift;; # Default is to append
    before) prepend=true; shift;;
  esac

  for arg; do
    IFS=: # Split argument by path separator
    for dir in $arg; do
      # Canonicalise symbolic links
      dir=$({ cd -- "$dir" && { pwd -P || pwd; } } 2>/dev/null)
      if [ -z "$dir" ]; then continue; fi  # Skip non-existent directory
      case ":$PATH:" in
        *":$dir:"*) :;; # skip - already present
        *) if [ "$prepend" ]; then
           # ${prefix:+$prefix:} will expand to "" if $prefix is empty to avoid
           # starting with a ":".  Expansion is "$prefix:" if non-empty.
            prefix=${prefix+$prefix:}$dir
          else
            PATH=$PATH:$dir  # Append by default
          fi;;
      esac
    done
  done
  [ "$prepend" ] && PATH=$prefix:$PATH
}

0

POSIX 호환 방식은 다음과 같습니다.

# USAGE: path_add [include|prepend|append] "dir1" "dir2" ...
#   prepend: add/move to beginning
#   append:  add/move to end
#   include: add to end of PATH if not already included [default]
#          that is, don't change position if already in PATH
# RETURNS:
# prepend:  dir2:dir1:OLD_PATH
# append:   OLD_PATH:dir1:dir2
# If called with no paramters, returns PATH with duplicate directories removed
path_add() {
    # use subshell to create "local" variables
    PATH="$(path_unique)"
    export PATH="$(path_add_do "$@")"
}

path_add_do() {
    case "$1" in
    'include'|'prepend'|'append') action="$1"; shift ;;
    *)                            action='include'   ;;
    esac

    path=":$PATH:" # pad to ensure full path is matched later

    for dir in "$@"; do
        #       [ -d "$dir" ] || continue # skip non-directory params

        left="${path%:$dir:*}" # remove last occurrence to end

        if [ "$path" = "$left" ]; then
            # PATH doesn't contain $dir
            [ "$action" = 'include' ] && action='append'
            right=''
        else
            right=":${path#$left:$dir:}" # remove start to last occurrence
        fi

        # construct path with $dir added
        case "$action" in
            'prepend') path=":$dir$left$right" ;;
            'append')  path="$left$right$dir:" ;;
        esac
    done

    # strip ':' pads
    path="${path#:}"
    path="${path%:}"

    # return
    printf '%s' "$path"
}

# USAGE: path_unique [path]
# path - a colon delimited list. Defaults to $PATH is not specified.
# RETURNS: `path` with duplicated directories removed
path_unique() {
    in_path=${1:-$PATH}
    path=':'

    # Wrap the while loop in '{}' to be able to access the updated `path variable
    # as the `while` loop is run in a subshell due to the piping to it.
    # https://stackoverflow.com/questions/4667509/shell-variables-set-inside-while-loop-not-visible-outside-of-it
    printf '%s\n' "$in_path" \
    | /bin/tr -s ':' '\n'    \
    | {
            while read -r dir; do
                left="${path%:$dir:*}" # remove last occurrence to end
                if [ "$path" = "$left" ]; then
                    # PATH doesn't contain $dir
                    path="$path$dir:"
                fi
            done
            # strip ':' pads
            path="${path#:}"
            path="${path%:}"
            # return
            printf '%s\n' "$path"
        }
}

그것은에서 cribbed입니다 기욤 페로 - 라르 샹보 의 대답 이 질문mike511 의 대답은 여기 .

2017-11-23 업데이트 : @Scott 당 버그 수정


나는 prepending과 postpending (appending) 중에서 선택할 수있는 명령 행 옵션을 제공하기 위해 이것을 찬성하려고했다. 그러나 나는 생각했다 : 이것은 설명이없는 끔찍한 암호 코드입니다. (그리고 하나가 PATH를 변경하고 새 값을 에코, 다른 어디 당신이 두 가지 기능을 가지고 있다는 사실 그 출력을 캡처 하고 다시 PATH에 할당은 , 단지 불필요한 복잡성입니다.) ... (계속)
스콧

(계속)… 그리고 나는 연결이 잘못되었음을 알았습니다. (그리고 왜 당신이 그 사람들을 비난하고 있는지 잘 모르겠습니다. 당신은 그들의 답변에서 많은 것을 복사하지 않은 것 같습니다.) 그리고 코드 가 잘못되었음을 알았 습니다. 제대로 된 PATH 를 유지 관리 하는 것은 괜찮지 만 , 특히 잘 깨지지 않은 경우 이미 잘 구성되어 있다는 보장은 없습니다 /etc/profile. PATH에 추가하려는 디렉토리가 이미 두 번 이상 있을 수 있으며 코드가 질식합니다. … (계속)
Scott

당신이 앞에 추가하려고하면 (계속) ... 예를 들어, /a/ck/b:/a/ck:/tr:/a/ck, 당신은 얻을 /a/ck:/b:/a/ck:/tr:/tr:/a/ck.
Scott
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.