Znajdź ścieżkę bezwzględną ze skryptu

10

W skrypcie dostaję $0możliwą względną ścieżkę do niego. Aby przekonwertować go na wartość absolutną, znalazłem rozwiązanie, którego nie rozumiem:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

Moim problemem jest magia wewnątrz ${0%/*}i ${0##*/}. Wygląda na to, że pierwszy wyodrębnia nazwę katalogu, a drugi wyodrębnia nazwę pliku, po prostu nie rozumiem, jak to zrobić.

maaartinus
źródło
2
Używa rozszerzenia parametrów, ale nie działało to dla mnie. Jeśli twój skrypt będzie używany tylko w systemie Linux, możesz użyć go, readlink -f $0aby uzyskać ścieżkę kanoniczną.
Shawn J. Goff
1
@Shawn: 1 wielki głos na komentarz, ponieważ wprowadziłeś właściwe myślenie: „To używa rozszerzenia parametrów, ale to nie działało dla mnie”. dirnameUtil jest tu przydatna.
D4RIO,
mywiki.wooledge.org/BashFAQ/028 i cyberciti.biz/faq/… mówi, że BASH_SOURCEjest lepsza niż $0, ponieważ $0daje użytkownikowi wpisane polecenie, które może nie być aktualnie wykonywanym skryptem.
Joel Purra

Odpowiedzi:

8

Definicje:

${string%substring} usuwa najkrótsze dopasowanie $substringz końca $string.

${string##substring}usuwa najdłuższe dopasowanie $substringod początku $string.

Twój przykład:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

${0%/*} usuwa wszystko po ostatnim ukośniku, podając nazwę katalogu skryptu (która może być ścieżką względną).

${0##*/} usuwa wszystko do ostatniego ukośnika, podając tylko nazwę skryptu.

To polecenie zmienia katalog na skrypt i łączy bieżący katalog roboczy (podany przez $PWD) oraz nazwę skryptu, podając bezwzględną ścieżkę.

Aby zobaczyć, co się dzieje, spróbuj:

echo ${0%/*}
echo ${0##*/}
dogbane
źródło
Dodaj podwójne cudzysłowy wokół wszystkich rozszerzeń zmiennych, aby poradzić sobie z (prawie wszystkimi) nazwami plików zawierającymi znaki specjalne powłoki.
Gilles „SO- przestań być zły”
10

Shawn miał najprostsze rozwiązanie: readlink -f $0. Jeśli chcesz mieć absolutną pewność obsługi dziwnych nazw plików, możesz użyć tego:

absolute_path_x="$(readlink -fn -- "$0"; echo x)"
absolute_path="${absolute_path_x%x}"

Dokumentacja

l0b0
źródło
1
Dobrze widzieć poprawnie obsługiwane końcowe wiersze. Niestety readlink -fnjest specyficzny dla Linuksa, NetBSD i OpenBSD.
Gilles „SO- przestań być zły”
4

Oto bezpieczniejszy i bardziej czytelny sposób wykonania tej pracy:

abspath=$(unset CDPATH && cd "$(dirname "$0")" && echo $PWD/$(basename "$0"))

Uwagi:

  • Jeśli $0jest to pusta nazwa pliku bez poprzedzającej ścieżki, oryginalny skrypt nie powiedzie się, ale podany tutaj będzie działał. (Nie stanowi to problemu, $0ale może występować w innych aplikacjach).
  • Każde z tych podejść zakończy się niepowodzeniem, jeśli ścieżka do pliku faktycznie nie istnieje. (Nie jest to problem $0, ale może występować w innych aplikacjach).
  • Jest unsetto niezbędne, jeśli użytkownik mógł to zrobić CDPATH.
  • W przeciwieństwie do readlink -flub realpath, będzie to działać na wersjach Unixa innych niż Linux (np. Mac OS X).
Matthias Fripp
źródło
2

Jeśli chcesz nauczyć się rozszerzenia parametrów powłoki, możesz przeczytać go tutaj , ale rozszerzenie nie zawsze jest dobrym wyborem. W tym przypadku prawie każdy system uniksowy ma 2 dobre narzędzia:

basename
dirname

Pierwszy wyodrębni nazwę pliku, a drugi wyodrębni ścieżkę, więc jeśli masz 0 USD, powiedz:

dirname $0

I dostaniesz ścieżkę.

Twoje zdrowie

D4RIO
źródło
nazwa_katalogu może zwracać ścieżki względne
opticyclic
0

Przedstawiamy pwd, wbudowane bash. Znalezione również w pakiecie GNU coreutils.

$ sh ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
$0: ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
cheeky binary from /home/jaroslav/tmp (/home/jaroslav/tmp)

$ cat /home/jaroslav/tmp/somewhere.sh

abs=$( cd `dirname "$0"` ; pwd -P)
absBin=$( cd `dirname "$0"` ; /bin/pwd -P)
echo \$0: $0
echo cheeky binary from $abs \($absBin\)
Ярослав Рахматуллин
źródło