Jak mogę czysto dodać do $ PATH?

31

Chciałbym znaleźć sposób dodania rzeczy do $ PATH, dla całego systemu lub dla pojedynczego użytkownika, bez potencjalnego wielokrotnego dodawania tej samej ścieżki.

Jednym z powodów, dla których warto to zrobić, jest dodanie dodatków .bashrc, które nie wymagają logowania, a także są bardziej przydatne w systemach, które używają (np.) lightdm, Które nigdy nie wywołuje .profile.

Zdaję sobie sprawę z pytań dotyczących usuwania duplikatów z $ PATH, ale nie chcę ich usuwać . Chciałbym sposób dodawać ścieżki tylko wtedy, gdy nie są one już obecne.

Złotowłosa
źródło
możliwy duplikat utrzymywania duplikatów poza $ PATH w źródle
Ciro Santilli 事件 改造 中心 法轮功 六四 事件
goldi, nie wiem dlaczego, ale widziałem twój pierwszy komentarz nawet z pustymi. Ale tak, prefiksy nazw również działają, bez obaw! Zamykanie w drugą stronę również jest w porządku.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Okej, dopóki dostaniesz moją wiadomość. Czasami takie odwrócenie powoduje nieco chaosu, myślę, że zobaczymy, co się stanie.
goldilocks,
Zobacz także Dodaj katalog do $ PATH, jeśli jeszcze go nie ma (na Super User ).
G-Man mówi „Przywróć Monikę”

Odpowiedzi:

35

Załóżmy, że nowa ścieżka, którą chcemy dodać, to:

new=/opt/bin

Następnie za pomocą dowolnej powłoki POSIX możemy sprawdzić, czy newjest już na ścieżce i dodać ją, jeśli nie jest:

case ":${PATH:=$new}:" in
    *:"$new":*)  ;;
    *) PATH="$new:$PATH"  ;;
esac

Zwróć uwagę na użycie dwukropków. Bez dwukropków moglibyśmy pomyśleć, że powiedzmy, że new=/binbył już na ścieżce, ponieważ wzór pasował do siebie /usr/bin. Chociaż ŚCIEŻKI zwykle zawierają wiele elementów, obsługiwane są również specjalne przypadki zer i jeden element ŚCIEŻKI. Sprawa ŚCIEŻKI początkowo nieposiadająca elementów (pusta) jest obsługiwana przez użycie ${PATH:=$new}przypisania PATHdo, $newjeśli jest pusta. Ustawienie wartości domyślnych parametrów w ten sposób jest cechą wszystkich powłok POSIX: patrz sekcja 2.6.2 dokumentacji POSIX .)

Funkcja wywoływalna

Dla wygody powyższy kod można wprowadzić w funkcję. Tę funkcję można zdefiniować w wierszu poleceń lub, aby była dostępna na stałe, umieścić w skrypcie inicjującym powłokę (dla użytkowników bash ~/.bashrc):

pupdate() { case ":${PATH:=$1}:" in *:"$1":*) ;; *) PATH="$1:$PATH" ;; esac; }

Aby użyć tej funkcji aktualizacji ścieżki, aby dodać katalog do bieżącej ŚCIEŻKI:

pupdate /new/path
John1024
źródło
@hammar OK. Dodałem do tego skrzynkę.
John1024
1
Możesz zapisać 2 rozróżnienia wielkości liter - por. unix.stackexchange.com/a/40973/1131 .
maxschlepzig
3
Jeśli PATHjest pusty, doda to pusty wpis (tj. Bieżący katalog) do PATH. Myślę, że potrzebujesz innej skrzynki.
CB Bailey,
2
@CharlesBailey Nie inny case. Po prostu zrób case "${PATH:=$new}". Zobacz moją odpowiedź na podobne awarie.
mikeserv
1
@ mc0e Dodałem przykład użycia funkcji powłoki, aby ukryć „szum linii”.
John1024
9

Utwórz plik o /etc/profile.dnazwie np. mypath.sh(Lub cokolwiek chcesz). Jeśli używasz lightdm, upewnij się, że jest to wykonalne, w przeciwnym razie użyj /etc/bashrclub plik pochodzący z tego samego. Dodaj do tego następujące funkcje:

checkPath () {
        case ":$PATH:" in
                *":$1:"*) return 1
                        ;;
        esac
        return 0;
}

# Prepend to $PATH
prependToPath () {
        for a; do
                checkPath $a
                if [ $? -eq 0 ]; then
                        PATH=$a:$PATH
                fi
        done
        export PATH
}

# Append to $PATH
appendToPath () {
        for a; do
                checkPath $a
                if [ $? -eq 0 ]; then
                        PATH=$PATH:$a
                fi
        done
        export PATH
}

Rzeczy na początku (poprzedzone) $ PATH mają pierwszeństwo przed tym, co następuje, i odwrotnie, rzeczy na końcu (dołączone) zostaną zastąpione przez to, co nastąpi wcześniej. Oznacza to, że jeśli $ PATH jest /usr/local/bin:/usr/bini istnieje plik wykonywalny gotchaw obu katalogach, /usr/local/bindomyślnie zostanie użyty ten w.

Możesz teraz - w tym samym pliku, w innym pliku konfiguracyjnym powłoki lub z wiersza poleceń - użyć:

appendToPath /some/path /another/path
prependToPath /some/path /yet/another/path

Jeśli jest to w .bashrc, zapobiegnie to pojawianiu się wartości więcej niż raz podczas uruchamiania nowej powłoki. Istnieje ograniczenie polegające na tym, że jeśli chcesz dołączyć coś, co zostało wcześniej przygotowane (tj. Przesunąć ścieżkę w obrębie $ PATH) lub odwrotnie, musisz to zrobić sam.

Złotowłosa
źródło
rozdzielenia programów $PATHz IFS=:ostatecznie jest bardziej elastyczny niż case.
mikeserv
@mikeserv Bez wątpienia. Jest to rodzaj hackowania dla caseIMO. Wyobrażam sobie, awkże tutaj też można by dobrze wykorzystać.
złotowłosa
Trafne spostrzeżenie. I, jak myślę, gawkmożna bezpośrednio przypisać $PATH.
mikeserv
5

Możesz to zrobić w ten sposób:

echo $PATH | grep /my/bin >/dev/null || PATH=$PATH:/my/bin

Uwaga: jeśli budujesz PATH z innych zmiennych, sprawdź, czy nie są one puste, ponieważ wiele powłok interpretuje „„ jak ”. .

przeciwdziałanie
źródło
+1 Według strony podręcznika -qPOSIX jest wymagany przez grep, ale nie wiem, czy to oznacza, że ​​nadal istnieją niektóre (nie POSIX) grep, które go nie mają.
złotowłosa
1
zauważ, że wzór grep jest zbyt szeroki. Rozważ użycie egrep -q "(^ |:) / my / bin (: | \ $)" zamiast grep / my / bin> / dev / null. Dzięki tej modyfikacji twoje rozwiązanie jest poprawne i myślę, że jest to bardziej czytelne rozwiązanie niż obecnie preferowana odpowiedź z @ john1024. Zauważ, że użyłem podwójnych cudzysłowów, więc zamiast/my/bin
mc0e
5

Ważną częścią kodu jest sprawdzenie, czy PATH zawiera określoną ścieżkę:

printf '%s' ":${PATH}:" | grep -Fq ":${my_path}:"

To znaczy, upewnij się, że każda ścieżka wewnątrz PATHjest oddzielona po obu stronach PATHseparatorem ( :), a następnie sprawdź ( -q), czy istnieje literalny ciąg ( -F) składający się z PATHseparatora, twojej ścieżki i innego PATHseparatora. Jeśli nie, możesz bezpiecznie dodać ścieżkę:

if ! printf '%s' ":${PATH-}:" | grep -Fq ":${my_path-}:"
then
    PATH="${PATH-}:${my_path-}"
fi

Powinno to być zgodne z POSIX i powinno działać z każdą ścieżką niezawierającą znaku nowej linii. Jest bardziej skomplikowany, jeśli chcesz, aby działał ze ścieżkami zawierającymi znak nowej linii, a jednocześnie jest zgodny z POSIX, ale jeśli masz grepobsługę -z, możesz z niego korzystać.

10b0
źródło
4

Od lat noszę tę małą funkcję w różnych ~/.profileplikach. Myślę , że został napisany przez sysadmina w laboratorium, w którym kiedyś pracowałem, ale nie jestem pewien. W każdym razie jest podobny do podejścia Goldilocka, ale nieco inny:

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

Aby dodać nowy katalog na początku PATH:

pathmunge /new/path

i do końca:

pathmunge /new/path after
terdon
źródło
To działa dla mnie! Ale zamieniłem na logikę, aby wstawić ją domyślnie po i zastąpić „przed”. :)
Kevin Pauli,
pathmunge jest częścią dystrybucji linux centos / etc / profile, ma parametr przed i po. Nie widzę tego w moim najnowszym ubuntu 16.
Kemin Zhou
Wygląda na to, że działa poprawnie na macOS 10.12 po /bin/grep->grep
Ben Creasy
4

AKTUALIZACJA:

Zauważyłem, że twoja własna odpowiedź ma osobną funkcję do dodawania lub dodawania do $PATH. Podobał mi się ten pomysł. Dodałem więc trochę obsługi argumentów. Poprawnie _ją też umieściłem:

_path_assign() { oFS=$IFS ; IFS=: ; add=$* ; unset P A ; A=
    set -- ${PATH:=$1} ; for p in $add ; do {
        [ -z "${p%-[AP]}" ] && { unset P A
                eval ${p#-}= ; continue ; }
        for d ; do [ -z "${d%"$p"}" ] && break
        done ; } || set -- ${P+$p} $* ${A+$p}
        done ; export PATH="$*" ; IFS=$oFS
}

% PATH=/usr/bin:/usr/yes/bin
% _path_assign \
    /usr/bin \
    /usr/yes/bin \
    /usr/bin/nope \
    -P \
    /usr/nope/bin \
    /usr/bin \
    -A \
    /nope/usr/bin \
    /usr/nope/bin

% echo $PATH

WYDAJNOŚĆ:

/usr/nope/bin:/usr/bin:/usr/yes/bin:/usr/bin/nope:/nope/usr/bin

Domyślnie będzie to -Awskazywać na $PATH, ale możesz zmienić to zachowanie, aby -Pnaprawić, dodając -Pdowolne miejsce na liście argumentów. Możesz przełączyć go z powrotem na -Adozowanie, wręczając go -Aponownie.

BEZPIECZNY EVAL

W większości przypadków zalecam, aby ludzie unikali jakiegokolwiek użycia eval. Ale to, jak sądzę, wyróżnia się na przykład na dobre. W tym przypadku jedynym stwierdzeniem, eval jakie kiedykolwiek można zobaczyć, jest P=lub A=. Wartości jego argumentów są ściśle sprawdzane przed wywołaniem. Po to eval jest.

assign() { oFS=$IFS ; IFS=: ; add=$* 
    set -- ${PATH:=$1} ; for p in $add ; do { 
        for d ; do [ -z "${d%"$p"}" ] && break 
        done ; } || set -- $* $p ; done
    PATH="$*" ; IFS=$oFS
}

To przyjmie tyle argumentów, ile podasz, i dodasz każdy z nich $PATHtylko raz i tylko wtedy, gdy jeszcze go nie ma $PATH. Wykorzystuje tylko w pełni przenośny skrypt powłoki POSIX, opiera się tylko na wbudowanych powłokach i jest bardzo szybki.

% PATH=/usr/bin:/usr/yes/bin
% assign \
    /usr/bin \
    /usr/yes/bin \
    /usr/nope/bin \
    /usr/bin \
    /nope/usr/bin \
    /usr/nope/bin

% echo "$PATH"
> /usr/bin:/usr/yes/bin:/usr/nope/bin:/nope/usr/bin
mikeserv
źródło
@ TAFKA'goldilocks 'zobacz aktualizację tutaj - zainspirowałeś mnie.
mikeserv
+1 Z ciekawości (być może byłoby to dobre osobne pytanie i odpowiedź), skąd wziął się pomysł, że _prefiksowanie funkcji powłoki powoduje, że są one odpowiednio rozmieszczone? W innych językach zwykle oznacza wewnętrzną funkcję globalną (to znaczy taką, która musi być globalna, ale nie jest przeznaczona do użytku zewnętrznego jako część interfejsu API). Moje imiona z pewnością nie są świetnymi wyborami, ale wydaje mi się, że samo użycie _wcale nie rozwiązuje problemów z kolizją - lepiej byłoby podać rzeczywistą przestrzeń nazw, np. mikeserv_path_assign().
złotowłosa
@ TAFKA „złote złociki” - lepiej byłoby z nim jeszcze bardziej sprecyzować, ale im dłużej nazwa staje się tym mniej wygodna, tym łatwiej jest z niej korzystać. Ale jeśli masz jakieś poprawne pliki binarne z prefiksem _, musisz zmienić menedżera pakietów. W każdym razie jest to po prostu „globalna, wewnętrzna funkcja” - jest globalna dla każdej powłoki wywoływanej z powłoki, w której została zadeklarowana, i jest tylko odrobiną zinterpretowanego skryptu językowego wiszącego w pamięci tłumacza . unix.stackexchange.com/questions/120528/…
mikeserv
Czy nie możesz unset a(lub odpowiednik) na końcu profilu?
sourcejedi
0

Ujrzeć! Wytrzymała przemysłowa 12-liniowa ... technicznie przenośna powłoka bash i zsh, która z oddaniem uwielbia wybrany przez Ciebie skrypt startowy ~/.bashrclub ~/.zshrcstartowy:

# void +path.append(str dirname, ...)
#
# Append each passed existing directory to the current user's ${PATH} in a
# safe manner silently ignoring:
#
# * Relative directories (i.e., *NOT* prefixed by the directory separator).
# * Duplicate directories (i.e., already listed in the current ${PATH}).
# * Nonextant directories.
+path.append() {
    # For each passed dirname...
    local dirname
    for   dirname; do
        # Strip the trailing directory separator if any from this dirname,
        # reducing this dirname to the canonical form expected by the
        # test for uniqueness performed below.
        dirname="${dirname%/}"

        # If this dirname is either relative, duplicate, or nonextant, then
        # silently ignore this dirname and continue to the next. Note that the
        # extancy test is the least performant test and hence deferred.
        [[ "${dirname:0:1}" == '/' &&
           ":${PATH}:" != *":${dirname}:"* &&
           -d "${dirname}" ]] || continue

        # Else, this is an existing absolute unique dirname. In this case,
        # append this dirname to the current ${PATH}.
        PATH="${PATH}:${dirname}"
    done

    # Strip an erroneously leading delimiter from the current ${PATH} if any,
    # a common edge case when the initial ${PATH} is the empty string.
    PATH="${PATH#:}"

    # Export the current ${PATH} to subprocesses. Although system-wide scripts
    # already export the ${PATH} by default on most systems, "Bother free is
    # the way to be."
    export PATH
}

Przygotujcie się na natychmiastową chwałę. Następnie, zamiast robić to i życzyć sobie najlepszego:

export PATH=$PATH:~/opt/bin:~/the/black/goat/of/the/woods/with/a/thousand/young

Zrób to zamiast tego i zapewnij sobie to, co najlepsze, niezależnie od tego, czy naprawdę tego chcesz, czy nie:

+path.append ~/opt/bin ~/the/black/goat/of/the/woods/with/a/thousand/young

Bardzo dobrze, określ „Najlepsze”.

Bezpieczne dołączanie i dopływanie do prądu ${PATH}nie jest banalną sprawą, na którą zwykle się składa. Choć wygodne i pozornie rozsądne, jednowarstwowe formy export PATH=$PATH:~/opt/binzachęcają do diabelskich komplikacji z:

  • Przypadkowe nazwy względne (np export PATH=$PATH:opt/bin.). Podczas gdy bashi zshpo cichu akceptuję i najczęściej ignoruję względne nazwy w większości przypadków, względne nazwy poprzedzone jednym hlub t(i prawdopodobnie innymi nikczemnymi bohaterami) powodują, że oba wstydliwie okaleczają się jako przełomowe arcydzieło Masakiego Kobayashiego z 1962 r. Harakiri :

    # Don't try this at home. You will feel great pain.
    $ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:harakiri && echo $PATH
    /usr/local/bin:/usr/bin:arakiri
    $ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:tanuki/yokai && echo $PATH
    binanuki/yokai   # Congratulations. Your system is now face-up in the gutter.
  • Przypadkowo zduplikowane nazwy. Chociaż zduplikowane ${PATH}nazwy są w dużej mierze nieszkodliwe, są również niepożądane, nieporęczne, nieco nieefektywne, utrudniają debuggowanie i promują zużycie dysku - coś w rodzaju takiej odpowiedzi. Podczas gdy dyski SSD w stylu NAND są ( oczywiście ) odporne na zużycie odczytu, dyski HDD nie są. Niepotrzebny dostęp do systemu plików przy każdej próbie polecenia oznacza niepotrzebne zużycie głowicy odczytu w tym samym tempie. Duplikaty są szczególnie nieprzyjemne, gdy wywołuje się zagnieżdżone skorupy w zagnieżdżonych podprocesach, w których to pozornie nieszkodliwe jednowarstwowe, jak export PATH=$PATH:~/watszybko, eksplodują w Siódmym Kręgu ${PATH}Piekła PATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat. Tylko Belzebubba może ci pomóc, jeśli do tego dodasz dodatkowe nazwy. (Nie pozwól, aby stało się to z twoimi cennymi dziećmi. )

  • Przypadkowo brakuje nazwisk. Ponownie, chociaż brakujące ${PATH}nazwy są w dużej mierze nieszkodliwe, zazwyczaj są one również niepożądane, nieporęczne, lekko nieefektywne, utrudniają debuggowanie i sprzyjają zużyciu dysku.

Ergo, przyjazna automatyzacja, taka jak funkcja powłoki zdefiniowana powyżej. Musimy uratować się od siebie.

Ale ... Dlaczego „+ path.append ()”? Dlaczego nie po prostu append_path ()?

Dla disambiguity (na przykład za pomocą poleceń zewnętrznych obecnych ${PATH}lub na cały system funkcji powłoki zdefiniowane gdzie indziej), funkcje powłoki zdefiniowane przez użytkownika są idealnie przedrostkiem lub przyrostkiem unikalnych podciągów obsługiwanych przez bashi zsha, które są zabronione w standardzie basenames poleceń - takich jak, na przykład, +.

Hej. To działa. Nie osądzaj mnie.

Ale ... Dlaczego „+ path.append ()”? Dlaczego nie „+ path.prepend ()”?

Ponieważ ${PATH}dopływ do prądu jest bezpieczniejszy niż dopływ do prądu ${PATH}, wszystkie rzeczy są równe, którymi nigdy nie są. Zastępowanie poleceń systemowych za pomocą poleceń specyficznych dla użytkownika może być w najlepszym razie niehigieniczne, aw najgorszym stanie się szaleństwem. Na przykład w systemie Linux aplikacje podrzędne zwykle oczekują wariantów poleceń GNU coreutils , a nie niestandardowych niestandardowych pochodnych lub alternatyw.

To powiedziawszy, istnieją absolutnie uzasadnione przypadki użycia. Zdefiniowanie równoważnej +path.prepend()funkcji jest banalne. Sans prolix mgławica, bo on i jej wspólny rozsądek:

+path.prepend() {
    local dirname
    for dirname in "${@}"; do
        dirname="${dirname%/}"
        [[ "${dirname:0:1}" == '/' &&
           ":${PATH}:" != *":${dirname}:"* &&
           -d "${dirname}" ]] || continue
        PATH="${dirname}:${PATH}"
    done
    PATH="${PATH%:}"
    export PATH
}

Ale ... dlaczego nie Gilles?

Gilles ' Akceptowane odpowiedź gdzie indziej jest imponująco optymalna w ogólnym przypadku jako «shell agnostycznego idempotent append» . W przypadku wspólnego bashi zshze bez niepożądanych dowiązania jednak kara wydajność wymaga tego smuci się Ricer Gentoo we mnie. Nawet w obecności niepożądanych dowiązań symbolicznych można zastanawiać się, czy rozwidlenie jednej podpowłoki na add_to_PATH()argument jest warte potencjalnego wstawienia duplikatów dowiązań symbolicznych.

W przypadku ścisłych przypadków użycia, wymagających wyeliminowania nawet duplikatów dowiązań symbolicznych, ten zshwariant specyficzny robi to za pomocą wydajnych wbudowanych elementów zamiast nieefektywnych rozwidleń:

+path.append() {
    local dirname
    for   dirname in "${@}"; do
        dirname="${dirname%/}"
        [[ "${dirname:0:1}" == '/' &&
           ":${PATH}:" != *":${dirname:A}:"* &&
           -d "${dirname}" ]] || continue
        PATH="${PATH}:${dirname}"
    done
    PATH="${PATH#:}"
    export PATH
}

Uwaga *":${dirname:A}:"*raczej niż *":${dirname}:"*oryginał. :Ajest cudowny - zshniestety nieobecny pod większością innych powłok - w tym bash. Cytując man zshexpn:

Odp . : Zmień nazwę pliku na ścieżkę bezwzględną, podobnie jak amodyfikator, a następnie przekaż wynik przez funkcję realpath(3)biblioteki, aby rozwiązać dowiązania symboliczne. Uwaga: w systemach, które nie mają realpath(3)funkcji biblioteki, dowiązania symboliczne nie są rozwiązywane, więc w tych systemach ai Asą równoważne.

Żadnych dalszych pytań.

Nie ma za co. Ciesz się bezpiecznym ostrzałem. Zasługujesz teraz na to.

Cecil Curry
źródło
0

Oto moja wersja w stylu programowania funkcjonalnego.

  • Działa z każdą *PATHzmienną rozdzielaną dwukropkami , nie tylko PATH.
  • Nie ma dostępu do stanu globalnego
  • Działa tylko z / na jego niezmiennych wejściach
  • Tworzy jedno wyjście
  • Bez skutków ubocznych
  • Możliwość zapamiętania (w zasadzie)

Na uwagę zasługuje również:

  • Agnostyk dotyczący exporting; pozostawiono to dzwoniącemu (patrz przykłady)
  • Czysty bash; bez rozwidlenia
path_add () {
  # $ 1: Element, który ma się upewnić, że znajduje się w podanym ciągu ścieżki dokładnie raz
  # $ 2: Istniejąca wartość ciągu ścieżki („$ PATH”, a nie „PATH”)
  # 3 USD (opcjonalnie, cokolwiek): Jeśli podano, dołącz 1 USD; w przeciwnym razie dodaj
  #
  # Przykłady:
  # $ PATH eksportu = $ (path_add '/ opt / bin' "$ PATH”)
  # $ CDPATH = $ (path_add '/ Music' „$ CDPATH” at_end)

  local -r już_present = "(^ |:) $ {1} ($ | :)"
  if [["$ 2" = ~ $ już_present]]; następnie
    echo „2 USD”
  elif [[$ # == 3]]; następnie
    echo „$ {2}: $ {1}”
  jeszcze
    echo „$ {1}: $ {2}”
  fi
}
Phil Hudson
źródło
0

Ten skrypt umożliwia dodanie na końcu $PATH:

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

Lub dodaj na początku $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" ] && [ "$prefix" != "" ] && PATH=$prefix:$PATH
}
Tom Hale
źródło