Jestem trochę zaskoczony, że nikt jeszcze o tym nie wspominał, ale możesz użyć go readlink -fdo 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 -fKomenda (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/dirARG..PATHARGA/path/to/my/bin/dir.PATH/path/to/my/bin/dirPATH
Być może, co ważniejsze, głównym celem readlinkjest, 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.14nie ma go już w ŚCIEŻCE, wywołujemy readlinki 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 PATHpo raz drugi.
3. O co chodzi if ARGA=$(readlink -f "$ARG")?
W przypadku niejasności linia ta sprawdza, czy się readlinkpowiedzie. 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 readlinkzawiedzie - ale, jak omówiono w Jak odzyskać bezwzględną ścieżkę dowolnego pliku z OS X
i innych, readlinkjest 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 -fwydaje się, że nie działa w systemie Mac OS X 10.11.6, ale realpathdziała po wyjęciu z pudełka. ”Jeśli więc korzystasz z systemu, który go nie ma readlinklub gdzie readlink -fnie 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 -dtest ( [ -d "$ARGA" ]) jest prawdopodobnie prawdopodobnie niepotrzebny. Nie mogę wymyślić żadnego scenariusza, w którym $ARGkatalog jest readlinkudany, ale $ARGAnie jest katalogiem. Właśnie skopiowałem i wkleiłem pierwsze ifzdanie, aby utworzyć trzecie, i zostawiłem -dtest 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_profilei .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 pathappendpoleceniu, a nie mysql? I to pathappendnic 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
}