Usuń nadmiarowe ścieżki ze zmiennej $ PATH

125

Zdefiniowałem tę samą ścieżkę w zmiennej $ PATH 6 razy.

Nie wylogowywałem się, żeby sprawdzić, czy zadziałało.

Jak mogę usunąć duplikaty?

Zmienna $ PATH wygląda następująco:

echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/flacs/Programmes/USFOS/bin:/home/flacs/Programmes/USFOS/bin:/home/flacs/Programmes/USFOS/bin:/home/flacs/Programmes/USFOS/bin:/home/flacs/Programmes/USFOS/bin:/home/flacs/Programmes/USFOS/bin

Jak bym zresetował to do just

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
Charles Hendry
źródło
gdzie zdefiniowałeś to 6 razy? w jakich plikach?
hovanessyan
3
możliwy duplikat Jaki jest najbardziej elegancki sposób usunięcia ścieżki ze zmiennej $ PATH w Bash?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

122

Po prostu wykonujesz:

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

dotyczy to bieżącej sesji, jeśli chcesz zmienić na stałe, dodaj ją do dowolnego pliku .bashrc, bash.bashrc, / etc / profile - cokolwiek pasuje do twojego systemu i potrzeb użytkownika.

Uwaga: dotyczy to systemu Linux. Wyjaśnimy to nowym programistom. (`, ') Nie próbuj ustawiać = tych.

hovanessyan
źródło
tak, ustawiłem je na stałe w bash.bashrc. Czy więc polecenie powinno wyglądać mniej więcej tak? echo 'export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games' >> ~/.bashrc
charles hendry
chodzi o to, że w zależności od systemu operacyjnego wykonywany jest łańcuch konfiguracji. Musisz upewnić się, że zmienna PATH nie zostanie później nadpisana. Najłatwiejszym sposobem (dla jednego użytkownika) jest nadpisanie go w osobistym pliku .bashrc użytkownika, który zwykle znajduje się w jego katalogu domowym.
hovanessyan
1
twoje polecenie ustawia PATH na - $ PATH (bieżąca wartość PATH) + ciąg / usr / local / sbin: / usr / local / bin: / usr / sbin: / usr / bin: / sbin: / bin: / usr / gam‌ es. Jeśli chcesz mieć tylko łańcuch, usuń $ PATH + średnik (:) z polecenia. Nie ma znaczenia, czy używasz echo, czy ręcznie edytujesz plik ~ / .bashrc.
hovanessyan
plik bash.bashrc znajduje się w folderze / etc. Nie wyświetla jednak zmiennej $ PATH, więc nie jestem pewien, gdzie ją edytować
Charles Hendry
w swoim pierwszym komentarzu odbierasz echo do ~ / .bashrc (cytując: >> ~ / .bashrc), a nie do /etc/bash.bashrc. Jeśli chcesz zmienić ŚCIEŻKĘ dla określonego użytkownika, edytuj ją w / home / <nazwa użytkownika> /. Bashrc. /etc/bash.bashrc dotyczy wszystkich użytkowników.
hovanessyan
70

Jeśli używasz Bash, możesz również wykonać następujące czynności, jeśli, powiedzmy, chcesz usunąć katalog /home/wrong/dir/ze swojej PATHzmiennej:

PATH=`echo $PATH | sed -e 's/:\/home\/wrong\/dir\/$//'`
sufinawaz
źródło
1
Było to dla mnie przydatne, ponieważ w / etc / profile został dodany katalog, który chciałem wykluczyć, ale nie mam dostępu do / etc. Dzięki :)
Samizdis
13
Protip: możesz użyć innego separatora w wyrażeniu sed, aby uniknąć PATH=$(echo $PATH | sed -e 's|:/home/wrong/dir|$||')
znaku
4
Ta sztuczka pomaga, gdy chcę od razu mieć nową ścieżkę PATH i nie chcę wylogowywać się z bieżącego terminala. Jednak, aby uniknąć pomyłek, należy poeksperymentować z poleceniem generującym PATH (tj. echo $PATH | sed -e 's/:\/home\/wrong\/dir\/$//') Przed przypisaniem go do PATH.
biocyberman
2
To nie zadziała, jeśli ścieżka do usunięcia jest pierwszą ścieżką w $PATH. Użyj tego:PATH=$(echo :$PATH: | sed -e 's,:/home/wrong/dir:,:,g' -e 's/^://' -e 's/:$//')
Robin Hsu,
nie działało $ PATH=echo $ PATH | sed -e 's /: \ / scratch \ / sjn \ / anaconda \ / bin \ / python \ / $ //' '`` do usuwania / scratch / sjn / anaconda / bin / python
Mona Jalal
13

Linux: Usuń nadmiarowe ścieżki ze zmiennej $ PATH

Linux From Scratch ma tę funkcję w / etc / profile

# Functions to help us manage paths.  Second argument is the name of the
# path variable to be modified (default: PATH)
pathremove () {
        local IFS=':'
        local NEWPATH
        local DIR
        local PATHVARIABLE=${2:-PATH}
        for DIR in ${!PATHVARIABLE} ; do
                if [ "$DIR" != "$1" ] ; then
                  NEWPATH=${NEWPATH:+$NEWPATH:}$DIR
                fi
        done
        export $PATHVARIABLE="$NEWPATH"
}

Ma to być używane z tymi funkcjami do dodawania do ścieżki, aby nie robić tego nadmiarowo:

pathprepend () {
        pathremove $1 $2
        local PATHVARIABLE=${2:-PATH}
        export $PATHVARIABLE="$1${!PATHVARIABLE:+:${!PATHVARIABLE}}"
}

pathappend () {
        pathremove $1 $2
        local PATHVARIABLE=${2:-PATH}
        export $PATHVARIABLE="${!PATHVARIABLE:+${!PATHVARIABLE}:}$1"
}

Prostym użyciem jest po prostu podanie pathremoveścieżki katalogu do usunięcia - ale pamiętaj, że musi ona dokładnie pasować:

$ pathremove /home/username/anaconda3/bin

Spowoduje to usunięcie każdej instancji tego katalogu ze ścieżki.

Jeśli chcesz, aby katalog znajdował się w Twojej ścieżce, ale bez redundancji, możesz po prostu użyć jednej z pozostałych funkcji, np. - w swoim konkretnym przypadku:

$ pathprepend /usr/local/sbin
$ pathappend /usr/local/bin
$ pathappend /usr/sbin
$ pathappend /usr/bin
$ pathappend /sbin
$ pathappend /bin
$ pathappend /usr/games

Ale o ile czytelność nie jest problemem, w tym momencie lepiej po prostu zrobić:

$ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

Czy powyższe zadziałałoby we wszystkich powłokach znanych człowiekowi?

Chciałbym przypuszczać powyższego do pracy w sh, dashi bashprzynajmniej. Byłbym zaskoczony, gdyby się dowiedział, że to nie działa csh, fish', orksh`. Wątpię, czy zadziałaby w powłoce poleceń Windows lub w Powershell.

Jeśli masz Pythona, poniższe polecenie powinno zrobić to, o co bezpośrednio zapytano (czyli usunąć nadmiarowe ścieżki):

$ PATH=$( python -c "
import os
path = os.environ['PATH'].split(':')
print(':'.join(sorted(set(path), key=path.index)))
" )

Jednowierszowy (aby uniknąć problemów wielowierszowych):

$ PATH=$( python -c "import os; path = os.environ['PATH'].split(':'); print(':'.join(sorted(set(path), key=path.index)))" )

Powyższe usuwa później zbędne ścieżki. Aby usunąć wcześniejsze nadmiarowe ścieżki, użyj indeksu odwróconej listy i ponownie go odwróć:

$ PATH=$( python -c "
import os
path = os.environ['PATH'].split(':')[::-1]
print(':'.join(sorted(set(path), key=path.index, reverse=True)))
" )
Aaron Hall
źródło
+1. czy pathremove () działa we wszystkich smakach powłoki, takich jak csh, ksh, bash itp? btw, mój / etc / profile na RHEL nie ma partremove (), ale ma tylko pathmunge ().
Tagar
1
@Tagar Nie gwarantuję zgodności ze wszystkimi innymi powłokami. Proponuję przetestować go na dowolnej powłoce, której używasz, a jeśli nie działa dla twojej powłoki, możesz użyć Pythona, jeśli masz go zainstalowanego - dodałem trochę Pythona do odpowiedzi, aby opisać, jak to zrobić.
Aaron Hall
Jeśli poprawnie przeczytałem „3.5.3 Rozszerzanie parametrów powłoki”, ${!PATHVARIABLE}jest to rodzaj zmiennej pośredniej, ale nie jestem pewien, jak to działa tutaj. Czy mógłbyś to wyjaśnić?
loxaxs
@loxaxs To lokalna zmienna w tych funkcjach basha, zadeklarowana za pomocą funkcji localwbudowanej (której można używać tylko wewnątrz funkcji). Jeśli masz dalsze pytania, prawdopodobnie powinieneś zadać nowe pytanie na stronie (po wyszukaniu go najpierw, aby upewnić się, że nie tworzysz dokładnego duplikatu ...).
Aaron Hall
To naprawdę ciekawa odpowiedź, dzięki za napisanie! Jednak pierwotna kwestia wyczyszczenia pomieszanej zmiennej PATH nie wydaje się być elegancko rozwiązana (chociaż, przyznaję, wtedy podczas korzystania z tych funkcji nie skończyłoby się pomieszaniem PATH).
Christian Herenz
9

Oto jeden wiersz kodu, który czyści PATH

  • Nie zakłóca kolejności PATH, po prostu usuwa duplikaty
  • Smakuje: i z wdziękiem emanuje PATH
  • Brak znaków specjalnych, więc nie wymaga ucieczki
  • Używa, /bin/awkwięc działa nawet wtedy, gdy PATH jest uszkodzony

    export PATH="$(echo "$PATH" |/bin/awk 'BEGIN{RS=":";}
    {sub(sprintf("%c$",10),"");if(A[$0]){}else{A[$0]=1;
    printf(((NR==1)?"":":")$0)}}')";
GreenFox
źródło
1
ktoś to przetestował? jest bezpieczny?
Joe RR
2
jeśli nie masz zainstalowanego awk czyści swoją ścieżkę, radzę Kopiowanie ścieżkę do pliku txt, zanim z echo $ PATH
José Pita
Nie działa dla mnie ... Mam zainstalowany awk, ale niektóre duplikaty nie są usuwane.
Christian Herenz,
3
  1. Właśnie echo $PATH
  2. skopiuj szczegóły do ​​edytora tekstu
  3. usuń niechciane wpisy
  4. PATH= # pass new list of entries
mrwagaba
źródło
2

Jeśli chcesz tylko usunąć zduplikowane ścieżki, używam tego skryptu, który napisałem jakiś czas temu, ponieważ miałem problem z wieloma ścieżkami perl5 / bin:

#!/bin/bash
#
# path-cleanup
#
# This must be run as "source path-cleanup" or ". path-cleanup"
# so the current shell gets the changes.

pathlist=`echo $PATH | sed 's/:/\n/g' | uniq`

# echo "Starting PATH: $PATH"
# echo "pathlist: $pathlist"
unset PATH
# echo "After unset, PATH: $PATH"
for dir in $pathlist
do
    if test -d $dir ; then
        if test -z $PATH; then
            PATH=$dir
        else
            PATH=$PATH:$dir
        fi
    fi
done
export PATH
# echo "After loop, PATH: $PATH"

I umieściłem to w moim ~ / .profile na końcu. Ponieważ używam BASH prawie wyłącznie, nie próbowałem go w innych powłokach.

Kevin Nathan
źródło
1
+1 za rozwiązanie. Przy okazji, usunie ścieżki duplikatów tylko wtedy, gdy pojawią się na liście jedna po drugiej. Możesz zmienić |uniqna, |sort|uniqaby to naprawić, ale spowoduje to zmianę kolejności wszystkich katalogów w ścieżce, co moim zdaniem nie jest pożądanym efektem ubocznym.
Tagar
1

Zakładając, że twoja powłoka to Bash, możesz ustawić ścieżkę za pomocą

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

ale jak powiedział Levon w innej odpowiedzi, jak tylko zakończysz działanie powłoki, zmiany znikną. Prawdopodobnie chcesz skonfigurować swój PATHw ~/.bash_profilelub ~/.bashrc.

Lew
źródło
1

W bashu możesz po prostu $ {var / find / replace}

PATH=${PATH/%:\/home\/wrong\/dir\//}

Lub w tym przypadku (ponieważ bit wymiany jest pusty) po prostu:

PATH=${PATH%:\/home\/wrong\/dir\/}

Przyjechałem tutaj pierwszy, ale poszedłem dalej, ponieważ myślałem, że nastąpi rozszerzenie parametrów aby to zrobić. Łatwiejsze niż sed !.

Jak zamienić znak zastępczy lub słowo w zmiennej na wartość z innej zmiennej w Bash?

sabgenton
źródło
%oznacza dopasowanie, jeśli na końcu łańcucha, #jest na początku.
Sabgenton
0

Nie ma standardowych narzędzi do „edycji” wartości $PATH(np. „Dodaj folder tylko wtedy, gdy jeszcze nie istnieje” lub „usuń ten folder”).

Aby sprawdzić, jaka byłaby ścieżka podczas następnego logowania, użyj telnet localhost(lub telnet 127.0.0.1). Następnie poprosi o podanie nazwy użytkownika i hasła.

To daje ci nową powłokę logowania (tj. Zupełnie nową, która nie dziedziczy niczego z obecnego środowiska).

Możesz sprawdzić wartość $PATHtam i edytować pliki rc, aż będzie poprawna. Jest to również przydatne, aby sprawdzić, czy w ogóle możesz się zalogować ponownie po wprowadzeniu zmiany w ważnym pliku.

Aaron Digulla
źródło
Zamiast wpisywać nazwę użytkownika / hasło, po prostu wpisz /bin/bash -i. Dużo mniej kłopotów.
Ed Heal
0

Jak dodałeś te zduplikowane ścieżki do zmiennej PATH? Musisz edytować jeden ze swoich .plików. ( .tcshrclub .bashrc, itp., w zależności od konkretnego systemu / powłoki). Aby to naprawić, należy ponownie wyedytować plik i usunąć zduplikowane ścieżki.

Jeśli nie edytowałeś żadnych plików i musisz interaktywnie zmodyfikować PATH. W takim przypadku zmiany nie zostaną „zachowane”, tj. Jeśli otworzysz inną powłokę lub wylogujesz się i zalogujesz ponownie, zmiany znikną automatycznie.

Zauważ, że istnieją również pliki konfiguracyjne dla całego systemu, ale jest mało prawdopodobne, że je zmodyfikowałeś, więc najprawdopodobniej będziesz zmieniać pliki w swoim osobistym katalogu domowym (jeśli chcesz, aby te zmiany stały się trwałe po ustaleniu zestawu ścieżek)

Levon
źródło
0

Aby uzyskać łatwy szablon kopiuj-wklej, używam tego fragmentu kodu Perl:

PATH=`echo $PATH | perl -pe s:/path/to/be/excluded::`

W ten sposób nie musisz uciekać przed ukośnikami dla operatora zastępczego.

Alexander Shcheblikin
źródło