Czy ktoś napisał funkcję bash, aby dodać katalog do $ PATH tylko wtedy, gdy jeszcze go nie ma?
Zazwyczaj dodaję do PATH używając czegoś takiego:
export PATH=/usr/local/mysql/bin:$PATH
Jeśli zbuduję ŚCIEŻKĘ w .bash_profile, to nie zostanie odczytana, chyba że sesja, w której jestem, to sesja logowania - co nie zawsze jest prawdą. Jeśli zbuduję moją ŚCIEŻKĘ w .bashrc, to działa ona z każdą podpowłoką. Jeśli więc uruchomię okno terminala, a następnie uruchomię ekran, a następnie uruchom skrypt powłoki, otrzymuję:
$ echo $PATH
/usr/local/mysql/bin:/usr/local/mysql/bin:/usr/local/mysql/bin:....
Spróbuję zbudować funkcję bash o nazwie, add_to_path()
która dodaje katalog tylko wtedy, gdy go nie ma. Ale jeśli ktoś już napisał (lub znalazł) coś takiego, nie spędzę na tym czasu.
Odpowiedzi:
Z mojego .bashrc:
Pamiętaj, że PATH powinien być już oznaczony jako wyeksportowany, więc ponowny eksport nie jest potrzebny. To sprawdza, czy katalog istnieje i jest katalogiem przed dodaniem go, co może Cię nie obchodzić.
Ponadto dodaje to nowy katalog na końcu ścieżki; na początek, użyj
PATH="$1${PATH:+":$PATH"}"
zamiast powyższejPATH=
linii.źródło
":$PATH:"
zamiast po prostu"$PATH"
${PATH:+"$PATH:"}
$ 1”${variable:+value}
oznacza sprawdzenie, czyvariable
jest zdefiniowane i ma niepustą wartość, a jeśli tak, daje wynik ocenyvalue
. Zasadniczo, jeśli PATH jest niepuste na początku, ustawia ją na"$PATH:$1"
; jeśli jest pusty, ustawia go tylko"$1"
(zauważ brak dwukropka).Rozwijając odpowiedź Gordona Davissona, obsługuje wiele argumentów
Więc możesz zrobić pathappend path1 path2 path3 ...
Do przygotowania
Możesz to zrobić podobnie do pathappend
ścieżkaprepend ścieżka1 ścieżka2 ścieżka3 ...
źródło
pathprepend P1 P2 P3
i skończyć zPATH=P1:P2:P3
. Aby uzyskać takie zachowanie, zmieńfor ARG in "$@" do
nafor ((i=$#; i>0; i--)); do ARG=${!i}
Oto moja odpowiedź na to pytanie w połączeniu ze strukturą funkcji Douga Harrisa. Używa wyrażeń regularnych Bash:
źródło
$1
zamiast${1}
Umieść to w komentarzach do wybranej odpowiedzi, ale wydaje się, że komentarze nie obsługują formatowania PRE, więc dodaj odpowiedź tutaj:
@ Gordon-Davisson Nie jestem wielkim fanem niepotrzebnych cytatów i konkatenacji. Zakładając, że używasz wersji bash> = 3, możesz zamiast tego użyć wbudowanych wyrażeń regularnych bash i wykonać:
To poprawnie obsługuje przypadki, w których w katalogu lub ŚCIEŻCE są spacje. Jest pewne pytanie, czy wbudowany silnik regex bash jest wystarczająco wolny, aby to mogło być mniej wydajne niż konkatenacja i interpolacja łańcuchów w porównaniu z twoją wersją, ale jakoś wydaje mi się bardziej czysta estetycznie.
źródło
formatting using the backtick
tylko, ale nie masz żadnej przyzwoitej kontroli akapitu.unnecessary quoting
oznacza, że wiesz z góry, że$PATH
nie jest zerowa."$PATH"
sprawia, że OK jest, czy ŚCIEŻKA ma wartość zerową, czy nie. Podobnie jeśli$1
zawiera znaki, które mogą pomylić parser poleceń. Użycie wyrażenia regularnego w cudzysłowie"(^|:)$1(:|$)"
zapobiega temu.[[
i]]
. Wolę cytować wszystko, co może ewentualnie trzeba być cytowane, chyba że powoduje to się nie powiedzie, ale wierzę, że ma rację i że cytuje naprawdę nie są potrzebne wokół$PATH
. Z drugiej strony wydaje mi się, że masz rację$1
.Gdy potrzebujesz $ HOME / bin, aby pojawił się dokładnie raz na początku ścieżki $ PATH i nigdzie indziej, nie akceptuj substytutów.
źródło
PATH=${PATH/"
... zamiastPATH=${PATH//"
... aby to zadziałało.$1
jest jedynym wpisem (bez dwukropków). Wpis zostaje podwojony.Oto alternatywne rozwiązanie, które ma dodatkową zaletę polegającą na usuwaniu zbędnych wpisów:
Pojedynczy argument tej funkcji jest dodawany do PATH, a pierwsza instancja tego samego ciągu jest usuwana z istniejącej ścieżki. Innymi słowy, jeśli katalog już istnieje na ścieżce, jest on promowany na przód, a nie dodawany jako duplikat.
Funkcja działa, przygotowując dwukropek do ścieżki, aby upewnić się, że wszystkie wpisy mają dwukropek z przodu, a następnie przygotowując nowy wpis do istniejącej ścieżki z usuniętym wpisem. Ostatnia część jest wykonywana przy użyciu
${var//pattern/sub}
notacji bash ; więcej szczegółów znajdziesz w instrukcji bash .źródło
/home/robert
w twojejPATH
a wamipathadd /home/rob
.Oto moja (wydaje mi się, że została napisana lata temu przez Oscara, administratora mojego starego laboratorium, wszystko mu się należy), była w moim baszkrze od wieków. Ma tę dodatkową zaletę, że pozwala na dodanie lub dodanie nowego katalogu według potrzeb:
Stosowanie:
źródło
Jeśli chodzi o dodawanie, podoba mi się rozwiązanie @ Russella, ale jest mały błąd: jeśli spróbujesz dodać coś takiego jak „/ bin” do ścieżki „/ sbin: / usr / bin: / var / usr / bin: / usr / local / bin: / usr / sbin „zastępuje” / bin: „3 razy (kiedy tak naprawdę w ogóle nie pasował). Łącząc naprawę tego z dołączającym rozwiązaniem @ gordon-davisson, otrzymuję to:
źródło
Prosty alias taki jak ten poniżej powinien załatwić sprawę:
Wystarczy podzielić ścieżkę na znak: i porównać każdy składnik z argumentem, który przekazujesz. Grep sprawdza pełne dopasowanie linii i wypisuje liczbę.
Przykładowe użycie:
Zamień polecenie echo na addToPath lub podobny alias / funkcję.
źródło
Zobacz Jak uniknąć powielania zmiennej ścieżki w csh? na StackOverflow dla jednego zestawu odpowiedzi na to pytanie.
źródło
Oto co przygotowałem:
Teraz w .bashrc mam:
Zaktualizowana wersja po komentarzu na temat tego, jak mój oryginał nie będzie obsługiwał katalogów ze spacjami (dzięki temu pytaniu za wskazanie mnie do używania
IFS
):źródło
PATH
zawiera spacje,*
,?
albo[
...]
.Documents and Settings
iProgram Files
), ale Unix wspierał ścieżki zawierające białe spacje jeszcze zanim istniało Windoze.Jestem trochę zaskoczony, że nikt jeszcze o tym nie wspominał, ale możesz użyć go
readlink -f
do konwersji ścieżek względnych na ścieżki bezwzględne i dodania ich do ŚCIEŻKI jako takiej.Na przykład, aby poprawić odpowiedź Guillaume Perrault-Archambault,
staje się
1. Podstawy - co to robi?
readlink -f
Komenda (między innymi) przekonwertować ścieżkę względną do ścieżki bezwzględnej. To pozwala ci zrobić coś takiego2. Dlaczego dwa razy testujemy obecność w ŚCIEŻCE?
Rozważmy powyższy przykład. Jeśli użytkownik powie z katalogu po raz drugi, będzie . Oczywiście nie będzie obecny w . Ale wtedy zostanie ustawiony na (bezwzględny ekwiwalent ścieżki ), który już jest w . Musimy więc unikać dodawania do drugiego razu.
pathappend .
/path/to/my/bin/dir
ARG
.
.
PATH
ARGA
/path/to/my/bin/dir
.
PATH
/path/to/my/bin/dir
PATH
Być może, co ważniejsze, głównym celem
readlink
jest, jak sama nazwa wskazuje, przyjrzenie się dowiązaniu symbolicznemu i odczytanie zawartej w nim ścieżki (tj. Wskazuje). Na przykład:Otóż, jeśli powiecie
pathappend /usr/lib/perl/5.14
, a macie już/usr/lib/perl/5.14
ŚCIEŻKĘ, to w porządku; możemy po prostu zostawić to tak, jak jest. Ale jeśli/usr/lib/perl/5.14
nie ma go już w ŚCIEŻCE, wywołujemyreadlink
i otrzymujemyARGA
=/usr/lib/perl/5.14.2
, a następnie dodajemy to doPATH
. Ale poczekaj chwilę - jeśli już powiedziałeśpathappend /usr/lib/perl/5.14
, to masz już/usr/lib/perl/5.14.2
ŚCIEŻKĘ i ponownie musimy to sprawdzić, aby uniknąć dodania goPATH
po raz drugi.3. O co chodzi
if ARGA=$(readlink -f "$ARG")
?W przypadku niejasności linia ta sprawdza, czy się
readlink
powiedzie. To tylko dobra, defensywna praktyka programowania. Jeśli zamierzamy wykorzystać dane wyjściowe polecenia m jako część polecenia n (gdzie m < n ), rozsądnie jest sprawdzić, czy polecenie m nie powiodło się i jakoś sobie z tym poradzić. Nie sądzę, że prawdopodobniereadlink
zawiedzie - ale, jak omówiono w Jak odzyskać bezwzględną ścieżkę dowolnego pliku z OS X i innych,readlink
jest wynalazkiem GNU. Nie jest on określony w POSIX, więc jego dostępność w Mac OS, Solaris i innych systemach uniksowych innych niż Linux jest wątpliwa. (W rzeczywistości właśnie przeczytałem komentarz, który mówi „readlink -f
wydaje się, że nie działa w systemie Mac OS X 10.11.6, alerealpath
działa po wyjęciu z pudełka. ”Jeśli więc korzystasz z systemu, który go nie mareadlink
lub gdziereadlink -f
nie działa, możesz to zmodyfikować skrypt do użyciarealpath
.) Instalując siatkę bezpieczeństwa, zwiększamy przenośność naszego kodu.Oczywiście, jeśli korzystasz z systemu, który nie ma
readlink
(lubrealpath
), nie będziesz chciał tego robić .pathappend .
Drugi
-d
test ([ -d "$ARGA" ]
) jest prawdopodobnie prawdopodobnie niepotrzebny. Nie mogę wymyślić żadnego scenariusza, w którym$ARG
katalog jestreadlink
udany, ale$ARGA
nie jest katalogiem. Właśnie skopiowałem i wkleiłem pierwszeif
zdanie, aby utworzyć trzecie, i zostawiłem-d
test bez lenistwa.4. Wszelkie inne komentarze?
Tak. Podobnie jak wiele innych odpowiedzi tutaj, ta sprawdza, czy każdy argument jest katalogiem, przetwarza go, jeśli jest, i ignoruje go, jeśli nie jest. Może to (lub nie musi) być odpowiednie, jeśli używasz
pathappend
tylko.
plików „ ” (takich jak.bash_profile
i.bashrc
) i innych skryptów. Ale, jak pokazała ta odpowiedź (powyżej), użycie jej interaktywnie jest całkowicie wykonalne. Będziesz bardzo zdziwiony, jeśli to zrobiszJak powiedziałem powyżej, dobrą praktyką jest obsługa błędów. Oto przykład:
źródło
readlink -f "$ARG"
. (2) Nie wiem, dlaczego tak się stało (szczególnie po pomyślnym zakończeniu-d "$ARG"
testu), ale możesz chcieć sprawdzić, czy sięreadlink
nie powiódł. (3) Wydaje się, że pomijaszreadlink
podstawową funkcję - mapowanie symbolicznej nazwy linku na „prawdziwą nazwę pliku”. Jeśli (na przykład)/bin
jest dowiązaniem symbolicznym/bin64
, powtarzane wywołania dopathappend /bin
mogą spowodować powiedzenie ŚCIEŻKI…:/bin64:/bin64:/bin64:/bin64:…
. Prawdopodobnie powinieneś (również) sprawdzić, czy nowa wartość$ARG
jest już wPATH
..
w moim przykładzie uważam, że można go uznać za kanoniczną nazwę pliku. Poprawny?readlink
nazwa wyraźnie wskazuje na ich cel - patrzy na dowiązanie symboliczne i odczytuje zawartą w nim nazwę ścieżki (tzn. Wskazuje na). (2) Powiedziałem , że nie wiem, dlaczegoreadlink
miałbym zawieść. Zwracałem ogólną uwagę na to, że jeśli skrypt lub funkcja zawiera wiele poleceń, a polecenie n ma katastrofalną awarię (lub w ogóle nie ma sensu), jeśli polecenie m nie powiedzie się (gdzie m < n ), rozsądną dobrą praktyką jest sprawdź, czy polecenie m nie powiodło się, i jakoś sobie z tym poradzić - przynajmniej… (ciąg dalszy)readlink
może się nie powieść, jeśli (a) nazwa katalogu zostanie zmieniona lub usunięta (przez inny proces) między Twoimi połączeniami dotest
ireadlink
lub (b) jeśli/usr/bin/readlink
zostanie usunięty (lub uszkodzony). (3) Wygląda na to, że brakuje ci mojego punktu. Nie zachęcam do powielania innych odpowiedzi; Mówię, że sprawdzając, czy oryginałARG
(z wiersza poleceń) jest już w środkuPATH
, ale nie powtarzając sprawdzania nowegoARG
(wyjścia zreadlink
), twoja odpowiedź jest niepełna, a zatem nieprawidłowa. … (Ciąg dalszy)źródło
Ten sposób działa dobrze:
źródło
Moje wersje mniej ostrożnie podchodzą do pustych ścieżek i nalegają, aby ścieżki były prawidłowe i katalogi, niż niektóre zamieszczone tutaj, ale znajduję dużą kolekcję prepend / append / clean / unique-ify / itp. funkcje powłoki, które będą przydatne do manipulacji ścieżkami. Cała partia, w obecnym stanie, jest tutaj: http://pastebin.com/xS9sgQsX (opinie i ulepszenia bardzo mile widziane!)
źródło
Możesz użyć perl one liner:
Oto w bash:
źródło
Lekko zmodyfikowałem odpowiedź Gordona Davissona, aby użyć aktualnego katalogu, jeśli nie został podany. Możesz więc po prostu zrobić
padd
z katalogu, który chcesz dodać do ŚCIEŻKI.źródło
Możesz sprawdzić, czy zmienna niestandardowa została ustawiona, w przeciwnym razie ustaw ją, a następnie dodaj nowe wpisy:
Oczywiście wpisy te mogą być nadal duplikowane, jeśli zostaną dodane przez inny skrypt, na przykład
/etc/profile
.źródło
Ten skrypt umożliwia dodanie na końcu
$PATH
:Lub dodaj na początku
$PATH
:źródło
Oto sposób zgodny z POSIX.
Jest żłobienia z Guillaume Perrault-Archambault „s odpowiedź na to pytanie i mike511 ” s odpowiedź tutaj .
AKTUALIZACJA 23.11.2017: Naprawiono błąd na @Scott
źródło
/etc/profile
. Katalog, który próbujesz dodać do PATH, może już tam być więcej niż jeden raz , a twój kod dusi się. … (Ciąg dalszy)/a/ck
się przygotować/b:/a/ck:/tr:/a/ck
, otrzymasz/a/ck:/b:/a/ck:/tr:/tr:/a/ck
.