Próbuję uzyskać bezwzględną ścieżkę do aktualnie uruchomionego skryptu w systemie OS X.
Widziałem wiele odpowiedzi readlink -f $0
. Jednak ponieważ OS X readlink
jest taki sam jak BSD, po prostu nie działa (działa z wersją GNU).
Czy jest na to gotowe rozwiązanie?
$( cd "$(dirname "$0")" ; pwd -P )
Odpowiedzi:
Jest
realpath()
funkcja C, która wykona zadanie, ale nie widzę niczego dostępnego w wierszu poleceń. Oto szybka i brudna wymiana:Spowoduje to wydrukowanie ścieżki dosłownie, jeśli zaczyna się od
/
. Jeśli nie, musi to być ścieżka względna, więc poprzedza ją na początku$PWD
.#./
Część Odcina./
się z przodu$1
.źródło
realpath ../something
powroty$PWD/../something
command -v realpath >/dev/null 2>&1 || realpath() { ... }
Te trzy proste kroki rozwiązują ten i wiele innych problemów z systemem OS X:
brew install coreutils
grealpath .
(3) można zmienić na zwykłe
realpath
, patrz (2) wyjścieźródło
$( cd "$(dirname "$0")" ; pwd -P )
dla mnie działają dobrze.XXX
i ktoścd xxx
potempwd
wróci.../xxx
. Z wyjątkiem tej odpowiedzi, wszystkie powyższe rozwiązania powracają,xxx
gdy naprawdę chceszXXX
. Dziękuję Ci!realpath
, to co się stanie, gdy prawie na pewno będziesz potrzebować innych przedmiotówcoreutils
? Przepisać te funkcje również w bash? : PFuj. Wydaje mi się, że poprzednie odpowiedzi były trochę nieciekawe z kilku powodów: w szczególności nie rozwiązują wielu poziomów dowiązań symbolicznych i są wyjątkowo „bash-y”. Podczas gdy pierwotne pytanie wyraźnie zawiera prośbę o „skrypt Bash”, wspomina się również o BSD systemu Mac OS X, który nie jest GNU
readlink
. Oto próba rozsądnego przenoszenia (sprawdziłem to z bash jako „sh” i myślnik), rozwiązując dowolną liczbę dowiązań symbolicznych; i powinno również działać z białymi znakami w ścieżce (ścieżkach), chociaż nie jestem pewien zachowania, jeśli jest spacja w podstawowej nazwie samego narzędzia, więc może, hm, unikaj tego?Mam nadzieję, że to może być dla kogoś przydatne.
źródło
local
dla zmiennych zdefiniowanych wewnątrz funkcji, aby nie zanieczyszczać globalnej przestrzeni nazw. Nplocal OURPWD=...
. Działa przynajmniej na bash.BASENAME=$(basename "$LINK")
wewnątrz while i użycie tego w drugim ustawiającym LINK i ustawiającym..
nadrzędnych w taki sposób, jakrealpath
by to zrobiło. Pocoreutils
zainstalowaniu homebrew spróbujln -s /var/log /tmp/linkexample
wtedyrealpath /tmp/linkexample/../
; to drukuje/private/var
. Ale/tmp/linkexample/..
zamiast tego twoja funkcja produkuje , ponieważ..
nie jest dowiązaniem symbolicznym.Bardziej przyjazny dla wiersza poleceń wariant rozwiązania Pythona:
źródło
python -c "import os; import sys; print(os.path.realpath(sys.argv[1]))"
Szukałem rozwiązania do wykorzystania w skrypcie obsługi systemu, tj. Uruchomionym przed zainstalowaniem Homebrew. Z braku odpowiedniego rozwiązania po prostu przeładowałbym zadanie do języka wieloplatformowego, np. Perl:
Częściej to, czego faktycznie chcemy, to katalog zawierający:
źródło
FULLPATH=$(perl -e "use Cwd 'abs_path'; print abs_path('$0')")
. Jakiś powód przeciwko?''
nie jest kuloodporny. Na przykład pęka, jeśli$0
zawiera pojedynczy cytat. Bardzo prosty przykład: wypróbuj swoją wersję/tmp/'/test.sh
i/tmp/'/test.sh
korzystaj z pełnej ścieżki./tmp/'.sh
.Ponieważ istnieje rzeczywista ścieżka, jak wskazywali inni:
Plik Makefile:
Następnie skompiluj
make
i umieść miękki link za pomocą:ln -s $(pwd)/realpath /usr/local/bin/realpath
źródło
gcc realpath.c -o /usr/local/bin/realpath
?/usr/local/bin
Użyj Pythona, aby to uzyskać:
źródło
dirname
poda nazwę katalogu/path/to/file
, tj/path/to
.cd /path/to; pwd
zapewnia, że ścieżka jest bezwzględna.basename
poda tylko nazwę pliku w/path/to/file
, tjfile
.źródło
Jak widać powyżej, zrobiłem to około 6 miesięcy temu. Zupełnie o tym zapomniałem, aż znowu potrzebowałem czegoś podobnego. Byłem całkowicie zszokowany, widząc, jakie to podstawowe; Od około roku uczę się bardzo intensywnie programować, ale często mam wrażenie, że może w ogóle niczego się nie nauczyłem, gdy sytuacja jest najgorsza.
Usunąłbym powyższe „rozwiązanie”, ale naprawdę podoba mi się to, że jest zapisem tego, ile naprawdę nauczyłem się w ciągu ostatnich kilku miesięcy.
Ale błądzę. Usiadłem i rozpracowałem to zeszłej nocy. Wyjaśnienie w komentarzach powinno wystarczyć. Jeśli chcesz śledzić kopię, nad którą nadal pracuję, możesz skorzystać z tego sedna. To prawdopodobnie robi to, czego potrzebujesz.
źródło
..
odniesieniami do nadrzędnych; np./foo/link_to_other_directory/..
jest rozstrzygany/foo
raczej jako niż jako rodzic ścieżki, na którą/foo/link_to_other_directory
wskazuje dowiązanie symboliczne .readlink -f
irealpath
rozwiąż każdy składnik ścieżki, zaczynając od katalogu głównego i aktualizując oczekujące docelowe łącza do pozostałych, które są nadal przetwarzane. Dodałem odpowiedź na to pytanie, ponownie implementując tę logikę.realpath dla Mac OS X
Przykład z powiązaną ścieżką:
Przykład z folderem domowym
źródło
..
nim nie daje właściwej odpowiedzi, więc dodałem sprawdzenie, czy podana ścieżka jest katalogiem:if test -d $path ; then echo $(cd "$path"; pwd) ; else [...]
"$(dirname $(dirname $(realpath $0)))"
ale działa, więc potrzebuję czegoś innego ...echo
...
odniesienia do rodziców przed rozstrzygnięciem dowiązań symbolicznych, a nie po; spróbuj tego zcoreutils
zainstalowanym homebrew , utwórz łącze iln -s /var/log /tmp/linkexample
uruchomrealpath /tmp/linkexample/../
; to drukuje/private/var
. Ale twoja funkcja produkuje/tmp/linkexample/..
zamiast tego, ponieważpwd
nadal pokazuje się/tmp/linkexample
po cd.W systemie macOS jedynym rozwiązaniem, jakie znalazłem, które niezawodnie obsługuje łącza symboliczne, jest użycie
realpath
. Ponieważ to wymagabrew install coreutils
, po prostu zautomatyzowałem ten krok. Moja realizacja wygląda następująco:Te błędy, jeśli nie zostały
brew
zainstalowane, ale możesz też po prostu je zainstalować. Po prostu nie czułem się komfortowo, automatyzując coś, co powoduje usunięcie z sieci dowolnego kodu rubinowego.Zwróć uwagę, że jest to automatyczna odmiana odpowiedzi Olega Micheeva .
Jeden ważny test
Jeden dobry test każdego z tych rozwiązań to:
ln -s
) do tego plikuCzy rozwiązanie odwołuje się do dowiązania symbolicznego i podaje oryginalny katalog? Jeśli tak, to działa.
źródło
Wydaje się, że działa to na OSX, nie wymaga żadnych plików binarnych i zostało pobrane stąd
źródło
Lubię to:
źródło
Potrzebowałem
realpath
zamiennika na OS X, takiego, który działa poprawnie na ścieżkach z linkami symbolicznymi i odniesieniami do rodziców, tak jakreadlink -f
by to zrobił . Obejmuje to rozwiązywanie dowiązań symbolicznych w ścieżce przed rozwiązywaniem odniesień nadrzędnych; np. jeśli zainstalowałeścoreutils
butelkę homebrew , uruchom:Zauważ, że
readlink -f
problem został rozwiązany/tmp/linkeddir
przed rozwiązaniem..
odniesienia do katalogu nadrzędnego. Oczywiściereadlink -f
na Macu też nie ma .Tak więc w ramach implementacji bash zaimplementowałem
realpath
ponownie to, co robicanonicalize_filename_mode(path, CAN_ALL_BUT_LAST)
wywołanie funkcji GNUlib , w Bash 3.2; jest to również wywołanie funkcji, którereadlink -f
wykonuje GNU :Obejmuje wykrywanie okrągłego łącza symbolicznego, kończące się, jeśli ta sama (pośrednia) ścieżka jest widziana dwukrotnie.
Jeśli wszystko, czego potrzebujesz
readlink -f
, to możesz użyć powyższego jako:Dla
realpath
, ja również potrzebne--relative-to
i--relative-base
wsparcie, które daje ścieżek względnych po canonicalizing:Umieściłem testy jednostkowe w mojej prośbie Code Review dla tego kodu .
źródło
Opierając się na komunikacji z komentatorem, zgodziłem się, że implementacja realpath jest bardzo trudna i nie ma trywialnego sposobu, zachowując się zupełnie tak samo jak Ubuntu.
Ale następująca wersja poradzi sobie z przypadkami narożnymi, na które najlepsza odpowiedź nie może i zaspokoi moje codzienne potrzeby na Macbooku. Umieść ten kod w swoim ~ / .bashrc i pamiętaj:
źródło
echo
. Po prostupwd
działa tak samo jakecho $(pwd)
bez konieczności tarło drugą kopię powłoki. Ponadto, brak cytowania argumentuecho
jest błędem (utracisz wszelkie początkowe lub końcowe spacje, wszelkie sąsiednie wewnętrzne białe znaki i rozwiniesz symbole wieloznaczne itp.). Zobacz więcej stackoverflow.com/questions/10067266/…realpath
żądasz nieistniejącego katalogu.dir=$(dirname "$1"); file=$(basename "$1")
zamiast dawno przestarzałej składni odwrotnego znaku. Zwróć także uwagę na prawidłowe cytowanie argumentów.