Jak uzyskać „realpath”, aby znaleźć mój symboliczny link?

13

Używam MacOSX- basha jako mojej powłoki. Mam dowiązanie symboliczne, utworzone w ten sposób:

ln -s /usr/bin/python python2 

Mam pakiet, który używa Python2 i chcę utworzyć łącze do symbolu w moim bieżącym katalogu roboczym, do /usr/bin/pythonktórego faktycznie należy Python2. Kiedy robię python2z linii poleceń, pojawia się ten błąd:

python2: realpath couldn't resolve "/usr/bin/python2"

Ale wywołanie go w ten ./python2sposób poprawnie rozwiązuje ścieżkę. Mój PATHma .w tym. W rzeczywistości zmodyfikowałem go do testowania, aby mieć tylko .w sobie.

Jak to rozwiązać? Dzięki!


Kontekst

Szereg sugerowanych poniżej rozwiązań nie będzie dla mnie działać. Starałem się wyjaśnić moje pytanie tak skoncentrowane i krótkie, jak to możliwe, aby ludzie nie utonęli w morzu tekstu, ale najwyraźniej muszę podać więcej informacji.

Próbuję rozwinąć pakiet, który sklonowałem z git. Oryginalny pakiet, git-multimailjest / został opracowany na pewnym wariancie systemu Linux (domyślam się Ubuntu). Próbowałem go zmodyfikować, aby móc go używać i jego pakietu testowego na MacOSX przy możliwie jak najmniejszej modyfikacji. Oto dlaczego niektóre z proponowanych rozwiązań nie są idealne:

  1. Jako root utwórz python2dowiązanie symboliczne w / usr / bin /. Szukam rozwiązania, które nie wymagałoby tego. Na początku była to oczywista opcja, ale chciałbym rozwiązania, które jak najmniej modyfikuje system hosta. Dlatego chciałem utworzyć tymczasowe dowiązanie symboliczne w bieżącym katalogu roboczym, dodać CWD (tj. .) Do mojej ścieżki, a następnie zniszczyć to po zakończeniu (tj. Dowiązanie symboliczne).

  2. Utwórz skrypt opakowania, aby wywoływał skrypt Pythona z istniejącym pythonem. Problem polega na tym, że znaczna część pakietu testowego używa rzeczywistych plików skryptowych jako plików wykonywalnych, w zależności od shebang w celu znalezienia właściwego środowiska wykonywania. Oznaczałoby to znaczną edycję pakietu testowego. W tym kontekście (patrz poniżej fragment struktury testowej) musiałbym dodać opakowanie dla każdego .pypliku; ponadto użytkownik / programista musiałby być świadomy różnych zasad korzystania z pakietu w zależności od systemu, w którym jest zainstalowany (tj. w MacOSX upewnij się, że nie używasz plików python bez wywoływania ich przez opakowanie lub jawne wywołanie /usr/bin/python file.py).

    #! /bin/sh
    
    D=$(cd $(dirname "$0") && pwd)
    MULTIMAIL="$D/../git-multimail/git_multimail.py"
    POST_RECEIVE="$D/../git-multimail/post-receive"
    
    TESTREPO=$("$D/create-test-repo")
    
    HOME="$D"
    XDG_CONFIG_HOME="$D"
    GIT_CONFIG_NOSYSTEM=1
    export HOME XDG_CONFIG_HOME GIT_CONFIG_NOSYSTEM
    
    cd $TESTREPO
    
    test_email() {
        REFNAME="$1"
        OLDREV="$2"
        NEWREV="$3"
        echo "$OLDREV" "$NEWREV" "$REFNAME" | USER=pushuser "$MULTIMAIL"
    
    } 
    
  3. Zmiana wszystkich python2odniesień do python. README to sugeruje, ale skutecznie czyni kontrolę wersji bezużyteczną, ponieważ system widzi zmianę jako nową wersję, podczas gdy w rzeczywistości nie jest (semantycznie).

Korzystałem (3), ale próbuję znaleźć lepsze rozwiązanie. Jestem skłonny zaakceptować, że tak właśnie jest (tzn. Nie ma odpowiedniego sposobu, aby wskazać „python2”, aby /usr/bin/pythonbył przenośny i dyskretny bez wielu zmian w pakiecie testowym i aktualnej strukturze).

Avery Chan
źródło
1
Hej! Justln -s /usr/bin/python /usr/bin/python2
enedil
Rzeczywiście rozwijam git-multimail w systemie Linux. Ale chętnie przyjmuję łatki i testery, aby działały na OS X. BTW, twój problem „python2” został już rozwiązany, ponieważ git-multimail akceptuje zarówno python2, jak i python3 :-).
Matthieu Moy
W rozszerzonym pytaniu wciąż brakuje istotnego szczegółu: jak wygląda linia shebang w skryptach wykonywalnych? Za git-multimail.pyto #!/usr/bin/env python2, więc jest (stosunkowo) prosty sposób to zrobić.
Alexis
@ komentarz enedil za nie działa, jednak ln -s /usr/bin/python2.7 /usr/local/bin/python2nie
Phylliida

Odpowiedzi:

3

Jeśli chcesz rozwiązać (lub zbadać) dowiązanie symboliczne, możesz użyć niezależnej od platformy biblioteki bash 'realpath-lib'. Domyślnie emuluje readlink i działa na Macu lub Unixie. Można go znaleźć na Github lub Bitbucket i jest bezpłatny.

Ale wygląda na to, że chcesz po prostu zrobić python2 (zamiast ./python2) z lokalnego (roboczego) katalogu. Można to zrobić za pomocą aliasu w pliku .bashrc, w przeciwnym razie konieczne będzie dodanie katalogu roboczego (zawierającego dowiązanie symboliczne) do zmiennej środowiskowej PATH. Można to również zrobić tylko dla bieżącej sesji lub w pliku .bashrc dla przyszłych sesji. To może być rozwiązanie dla konkretnego użytkownika.

Inną opcją, która działałaby dla wszystkich użytkowników, byłoby utworzenie dowiązania symbolicznego python2 do / usr / bin / python w innym katalogu na ścieżce, powiedzmy w / usr / local / bin. Być może coś takiego:

sudo ln -s /usr/bin/python /usr/local/bin/python2

Następnie każdy użytkownik lub skrypt powinien znaleźć komendy python lub python2. Oczywiście ta opcja wymaga uprawnień administratora (root) do zainstalowania.

AsymLabs
źródło
W końcu się poddałem. Jest zbyt wiele miejsc, które zakładają „python2” w kodzie i nie każde zlokalizowane rozwiązanie obejmuje wszystkie możliwości. Jest to najbardziej odpowiedni młot do tego gwoździa.
Avery Chan,
@ Bardzo, czy wypróbowałeś moje rozwiązanie? Czy był problem? To nie byłby zobowiązany do dodać python2do /usr/bin(choć mogę wyświetlić dodanie go jako poprawa, szczerze mówiąc).
Alexis
Można to zrobić za pomocą aliasu (...) Nie jest to możliwe, ponieważ alias wpływa tylko na wiersz poleceń, a nie na skrypty. Zobacz Jak zmienić domyślną wersję Pythona w Debianie 7.5?
Piotr Dobrogost
To nie jest poprawna odpowiedź, przynajmniej nie rozwiązuje problemu, który skłonił plakat do zadania pytania.
smaudet
16

Wydaje mi się, że używasz systemu Apple do zarządzania wieloma wersjami tego samego programu i przełączania się między nimi. Możesz osiągnąć to, co chcesz, mniej elegancko, ale bez problemów, za pomocą następującego skryptu o nazwie python2:

#!/bin/bash
exec /usr/bin/python "$@"

Ustaw go jako wykonywalny ( chmod +x python2), a będziesz w biznesie.

Wyjaśnienie problemu:

Po uruchomieniu /usr/bin/pythonznajduje się i wykonuje python2.7 w tym samym katalogu. Twoje łącze symboliczne kończy się niepowodzeniem, ponieważ system podąża za dowiązaniem symbolicznym do /usr/bin, a następnie szuka i nie może python2 tam znaleźć . Możesz przejść o krok dalej, używając „twardego linku” zamiast linku symbolicznego:

rm python2
ln /usr/bin/python python2

Teraz nie ma dowiązania symbolicznego, tylko dwie nazwy plików dla tego samego pliku (i-węzła). Ale teraz nie mogę wyświetlić następującego komunikatu:

python2: posix_spawn: /Users/alexis/.../python22.7: No such file or directory

Zauważ python22.7: Framework dodaje 2.7do utworzonej nazwy! Zamiast próbować to rozwikłać i skonfigurować las linków, który odpowiada jego oczekiwaniom, radzę trzymać się z daleka od ram zarządzania wersjami i skorzystać z sugerowanego powyżej rozwiązania.

PS. Może być lepsze rozwiązanie: jeśli wytłumaczysz, co musisz zrobić na początku (dlaczego musisz podać python2jako alias python), ktoś prawdopodobnie może ci pomóc w inny sposób. Jest to znane jako „problem XY” w żargonie wymiany stosów ...

Alexis
źródło
Po uruchomieniu /usr/bin/pythonznajduje i wykonuje Python2.7 w tym samym katalogu. To bardzo mylące stwierdzenie. Jeśli opisujesz przypadek, w którym /usr/bin/pythonznajduje się dowiązanie symboliczne, podaj bardziej szczegółowe informacje.
Piotr Dobrogost
to po prostu niesamowicie złe ..
Nicolas
Co jest niesamowicie złe?
Alexis
Tak, nie zostało tutaj wyraźnie wspomniane, że myślę, że / usr / bin / python tak naprawdę nie jest pythonem, po prostu szuka zainstalowanego Pythona dla MacOS (python2.7, który jest dowiązany do folderu frameworka). Podejrzewam, że @nicolas mówi, że fałszywa wersja Pythona jest niesamowicie zła - to całkiem hack i szkoda, że ​​Apple tego nie zrobił. ... chciałbym, żeby Apple nie zrobiło wielu rzeczy, które po prostu niszczą ich skądinąd doskonały system uniksowy.
smaudet
3

Próbować:

ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /usr/local/bin/python2
Liangmin Li
źródło
1
Nie wiem, dlaczego są coraz downvotes, jest to jedyne rozwiązanie, że pracował dla mnie
xApple
1

Możesz użyć polecenia Unix, readlinkaby znaleźć fizyczną ścieżkę do linków.

Przykłady

Powiedz, że mam następujący link:

$ ls -l /usr/bin/etags
lrwxrwxrwx. 1 root root 29 Dec 10 22:56 /usr/bin/etags -> /etc/alternatives/emacs.etags

$ ls -l /etc/alternatives/emacs.etags
lrwxrwxrwx. 1 root root 20 Dec 10 22:56 /etc/alternatives/emacs.etags -> /usr/bin/etags.ctags

$ ls -l /usr/bin/etags.ctags
lrwxrwxrwx. 1 root root 5 Dec 10 22:56 /usr/bin/etags.ctags -> ctags

  1. Aby znaleźć wartość, na którą wskazuje dowiązanie symboliczne

    $ readlink /usr/bin/etags
    /etc/alternatives/emacs.etags
    

    UWAGA: Powyższy wynik może być kolejnym linkiem. Aby rozwiązać ten problem, patrz punkt 2 poniżej.

  2. Aby znaleźć bezwzględną ścieżkę wartości, na którą wskazuje dowiązanie symboliczne

    $ readlink -f /usr/bin/etags
    /usr/bin/ctags
    
slm
źródło
0

Nie rozumiem - jak myślisz, czy link do opakowania jest w porządku, ale nie skrypt do pakowania ? Każdy z nich jest jedynie poziomem pośrednictwa. I czy nadal nie musisz instruować użytkowników, aby dzwonili tylko z określonego katalogu?

W każdym razie możesz uzyskać bieżący katalog roboczy w $PATH:

 echo "echo \"Hi! I'm python\"" >|./python 
 chmod +x ./python 
 PATH="${PWD}:${PATH}" 
 python

 #OUTPUT#
 Hi! I'm python

 rm python 
 python -V 
 ln -s /usr/bin/python2 ./python 
 python -V

 #OUTPUT#
 Python 3.4.0
 Python 2.7.6

 PATH="${PATH#"${PWD}:"}" 
 python -V

 #OUTPUT#
 Python 3.4.0

Proszę weź . z twojego $PATH. To okropny pomysł.

mikeserv
źródło
Dlaczego .w mojej $ PATH jest to zły pomysł? Jeśli umieszczę go na końcu, ostatnim miejscem, które będzie sprawdzane, będzie mój bieżący katalog roboczy (tj. `PATH =" $ {PATH}: $ {PWD} ". Skrypt otoki oznacza, że ​​dla każdego pliku Pythona muszę utworzyć dodatkowy plik. Link otoki do pliku wykonywalnego Pythona po prostu tworzy dla mnie jedną rzecz
Avery Chan
@AveryChan Nie sądzę. Skrypt opakowania może uzyskać funkcję powłoki lub alias o tej samej nazwie co plik wykonywalny. Może także --bind mountbyć wykonywalny w bieżącym katalogu lub (jak sądzę tylko w systemie Linux) nawet chrootw razie potrzeby. Ale . w $PATHpracach dla dowolnego katalogu i nie jest specyficzny. Jest to niebezpieczne dla twoich użytkowników. W każdym razie bardzo wyraźnie pokazałem, jak to zrobić powyżej. Nie spełnia twoich wymagań?
mikeserv
0

Re @alexis odpowiedź, wersja Pythona /usr/binnie jest prawdziwym pythonem.

Powinno to być widoczne na trzy sposoby:

  1. Błąd, który otrzymujemy, nie jest tym, który zwykle powoduje Python. Zachowanie Pythona nie polega na szukaniu innego Pythona, ale na uruchamianiu skryptów Pythona.

  2. Jeśli obliczysz shasum /usr/bin/pythoni faktycznie uruchamiany python2.7 :

shasum /usr/bin/python
3782d9ab14b35037c9c7fb665439a5fa695c54a6  /usr/bin/python
shasum /usr/bin/python2.7
476fa96c80ac26a85b2d3b01ddfd19e513660c2c  /usr/bin/python2.7

Oni są zupełnie inni. Ponadto rozmiary plików różnią się o ~ 20 000 bajtów:

ll /usr/bin/python
-rwxr-xr-x  1 root  wheel  66880 May 17  2019 /usr/bin/python

vs.

ll /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
-rwxr-xr-x  1 root  wheel  43104 May 17  2019 /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
  1. Na koniec możesz zdekompilować python2.7 i python oraz zbadać symbole. Jest to jednak trochę poza zakresem po prostu „jak dowiązać symbolicznie python2.7 do python2 na osx”.

Więc (jak wskazuje błąd) /usr/bin/pythonodwraca się i szuka /usr/bin/python2.7:

ll /usr/bin/python2.7
lrwxr-xr-x  1 root  wheel  75 Jul  1  2019 /usr/bin/python2.7 -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7

Właśnie dlatego następujące prace (dzięki uprzejmości @ liangmin-li):

    ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /usr/local/bin/python2
smaudet
źródło
Witamy na stronie. Możesz dodać wyjaśnienie, jak zobaczyć z przykładowego lswyjścia, że /usr/bin/python„nie jest to prawdziwy python”.
AdminBee
To trochę oczywiste, ale mogę zaktualizować, jak możemy to ustalić.
smaudet
Może być dla kogoś, kto zna rozmiar typowego pliku pythonbinarnego tłumacza, ale pamiętaj, że odpowiedzi tutaj powinny być przydatne dla bardziej ogólnej publiczności U&L ...
AdminBee
1
Zaktualizowałem moją próbkę. Udowodnienie tożsamości binarnej jest jednak trudnym problemem, dlatego tutaj nie zajmuję się tym w pełni (rozmiary mogą się różnić między wersjami, zachowania mogą się zmieniać - dowody zamieszczone w mojej zaktualizowanej odpowiedzi dotyczą tego, jak zachowuje się ten system w porównaniu do tego, w jaki sposób powinna się zachowywać instalacja waniliowego Pythona. Nie sądzę, aby odpowiedź na temat inżynierii wstecznej była odpowiednia lub naprawdę pomocna w tym przypadku. Ale zrozumiałem twój punkt widzenia.
smaudet