Uzyskaj ścieżkę bieżącego skryptu po uruchomieniu za pomocą dowiązania symbolicznego

58

Mam narzędzie składające się z kilku katalogów z niektórymi skryptami bash i plikami pomocniczymi, które zostaną wdrożone na kilku komputerach, ewentualnie w innym katalogu na każdym komputerze. Skrypty muszą mieć możliwość odwoływania się do ścieżek względem siebie, więc muszę mieć możliwość uzyskania ścieżki do aktualnie wykonywanego pliku.

Zdaję sobie sprawę z dirname $0idiomu, który działa idealnie, gdy mój skrypt jest wywoływany bezpośrednio. Niestety istnieje chęć stworzenia dowiązań symbolicznych do tych skryptów z zupełnie innego katalogu i nadal mieć względną logikę ścieżek.

Przykład ogólnej struktury suchej jest następujący:

/
 |-usr/local/lib
 |  |-foo
 |  |  |-bin
 |  |  |  |-script.sh
 |  |  |-res
 |  |  |  |-resource_file.txt
 |-home/mike/bin
 |  |-link_to_script (symlink to /usr/local/lib/foo/bin/script.sh)

Jak mogę w sposób wiarygodny odwoływać się /usr/local/lib/foo/res/resource_file.txtdo script.shtego, czy jest przywoływany przez /usr/local/lib/foo/bin/script.shczy ~mike/bin/link_to_script?

Mike Deck
źródło

Odpowiedzi:

79

Wypróbuj to jako rozwiązanie ogólnego zastosowania:

DIR="$(cd "$(dirname "$0")" && pwd)"

W konkretnym przypadku następujących dowiązań symbolicznych możesz również to zrobić:

DIR="$(dirname "$(readlink -f "$0")")"
Caleb
źródło
Działa idealnie i jest o wiele prostszy niż rzeczy, których próbowałem. Dzięki!
Mike Deck
@MikeDeck Enjoy. Zauważ, że naprawiłem niektóre problemy z cytowaniem od pierwszego opublikowania ... możesz skorzystać z opcji z najnowszej edycji w przypadku, gdy masz na swojej drodze spacje lub inne zwariowane postacie. Nawet jeśli nie ma to znaczenia dla tego projektu, możesz skopiować kod ze swoich własnych skryptów, a wybór najlepszej opcji jest wtedy ważny!
Caleb
1
Powinienem wyjaśnić, drugi działa doskonale. Pierwsze podane rozwiązanie nie działa w przypadku dowiązań symbolicznych w moim systemie.
Mike Deck
4
@MikeDeck: Pierwsze rozwiązanie działa w typowym przypadku, gdy różne katalogi są połączone symbolicznie jako część ścieżki, ale nie pomoże, jeśli końcowy plik binarny jest dowiązaniem symbolicznym. Tym zajmuje się drugi.
Caleb
1
Nie działa, jeśli plik skryptu to sourced (np. $ source ./sript.sh) Działa to w obu przypadkach:DIR="$(cd "$(dirname "$BASH_SOURCE")" && pwd)"
FractalSpace
7

jedna linia:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))
diyizm
źródło
2
Odpowiedzi w jednym wierszu zazwyczaj nie są najbardziej pomocne. Rozważ poszerzenie swojej odpowiedzi o wyjaśnienia, linki lub dokumentację, które dodatkowo wspierają proponowane rozwiązanie.
HalosGhost
1
właściwie nie musisz tego robić, wersja readlink oryginalnej odpowiedzi działa dobrze, jeśli w ogóle nie ma w niej dowiązania symbolicznego
THESorcerer
3

readlink -f nie działa dla mnie, mam ten błąd:

readlink: illegal option -- f
usage: readlink [-n] [file ...]

Ale to działa dobrze:

DIR="$(dirname "$(readlink "$0")")"
echo $DIR
Kevin Campion
źródło
3
Jesteś na komputerze Mac, co powinno odpowiedzieć na twoje pytanie .
Izaak
Tak, jestem na MacOs @isaac, ale nie mam żadnych pytań. Wysłałem polecenie, które działa po mojej stronie.
Kevin Campion
0

Jeden mały dodatek do powyższego skryptu. Opcja -P do pwd podąża za dowiązaniami symbolicznymi

DIR="$(cd "$(dirname "$0")" && pwd -P)"
użytkownik2108420
źródło
7
Działa to tylko wtedy, gdy dowiązanie symboliczne jest częścią struktury katalogów. Nie działa, gdy sam plik jest połączony.
Oliver Gondža