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,
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
PATH="${PATH:+"$PATH:"}$ARG"
fi
done
}
staje się
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. 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ś takiego
$ cd / path / to / my / bin / dir
$ pathappend .
$ echo „$ PATH”
<twoja_ stara_ścieżka> : / path / to / my / bin / dir
2. 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:
$ 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
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łujemy readlink
i otrzymujemy ARGA
= /usr/lib/perl/5.14.2
, a następnie dodajemy to do PATH
. 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 go PATH
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 prawdopodobnie readlink
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, ale realpath
działa po wyjęciu z pudełka. ”Jeśli więc korzystasz z systemu, który go nie ma readlink
lub gdzie readlink -f
nie działa, możesz to zmodyfikować skrypt do użycia realpath
.) Instalując siatkę bezpieczeństwa, zwiększamy przenośność naszego kodu.
Oczywiście, jeśli korzystasz z systemu, który nie ma readlink
(lub realpath
), 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 jest readlink
udany, ale $ARGA
nie jest katalogiem. Właśnie skopiowałem i wkleiłem pierwsze if
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 zrobisz
$ pathappend /usr/local/nysql/bin
$ mysql
-bash: mysql: command not found
Czy zauważyłeś, że powiedziałem nysql
w pathappend
poleceniu, a nie mysql
? I to pathappend
nic nie powiedział; po prostu cicho zignorował niewłaściwy argument?
Jak powiedziałem powyżej, dobrą praktyką jest obsługa błędów. Oto przykład:
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
}