Wie erreiche ich "realpath", um meinen symbolischen Link zu finden?

13

Ich verwende MacOSX bashals meine Shell. Ich habe einen symbolischen Link, der wie folgt erstellt wurde:

ln -s /usr/bin/python python2 

Ich habe ein Paket, das python2 verwendet, und ich möchte in meinem aktuellen Arbeitsverzeichnis eine Symbolverknüpfung erstellen, zu /usr/bin/pythonder eigentlich python2 gehört. Wenn ich python2von der Kommandozeile aus einen mache, bekomme ich folgenden Fehler:

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

Wenn Sie es jedoch so aufrufen, wird ./python2der Pfad korrekt aufgelöst. Mein PATHhat .drin. Tatsächlich habe ich es zum Testen so modifiziert, dass es nur .darin enthalten ist.

Wie löse ich das? Vielen Dank!


Kontext

Einige der unten vorgeschlagenen Lösungen funktionieren bei mir nicht. Ich habe versucht, meine Frage so konzentriert und kurz wie möglich zu formulieren, damit die Leute nicht in einem Meer von Texten ertrinken, aber ich muss eindeutig mehr Hintergrundinformationen liefern.

Ich versuche, ein Paket zu entwickeln, das ich aus git geklont habe. Das Originalpaket git-multimailist / wurde auf einer Linux-Variante entwickelt (ich vermute Ubuntu). Ich habe versucht, es zu modifizieren, um es und seine Testsuite unter MacOSX mit so wenig Modifikationen wie möglich verwenden zu können. Hier ist, warum einige der vorgeschlagenen Lösungen nicht ideal sind:

  1. Erstellen Sie als Root einen python2Symlink in / usr / bin /. Ich suche nach einer Lösung, die dies nicht erfordert. Dies war zu Beginn eine naheliegende Option, aber ich hätte gerne eine Lösung, die das Hostsystem so wenig wie möglich verändert. Aus diesem Grund wollte ich einen temporären Symlink im aktuellen Arbeitsverzeichnis erstellen, die CWD (dh .) meinem Pfad hinzufügen und diese anschließend löschen (dh den Symlink).

  2. Erstellen Sie ein Wrapper-Skript, um das Python-Skript mit dem vorhandenen Python aufzurufen. Das Problem dabei ist, dass ein Großteil der Testsuite die tatsächlichen script_files als ausführbare Dateien verwendet, abhängig von shebang, um die richtige Ausführungsumgebung zu finden. Dies würde eine erhebliche Bearbeitung der Testsuite bedeuten. In diesem Zusammenhang (siehe unten für einen Ausschnitt des Test-Frameworks) müsste ich für jede .pyDatei einen Wrapper hinzufügen ; Ferner müsste der Benutzer / Entwickler unterschiedliche Regeln für die Verwendung des Pakets kennen, je nachdem, auf welchem ​​System sie sich befinden (dh unter MacOSX sollten Sie die Python-Dateien nicht verwenden, ohne sie über den Wrapper aufzurufen oder explizit aufzurufen /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. Ändern aller python2Verweise auf python. Die README-Datei schlägt dies vor, aber dies macht die Versionskontrolle wirkungslos, da das System die Änderung als neue Version ansieht, obwohl dies (semantisch) nicht der Fall ist.

Ich habe (3) verwendet, aber ich versuche, eine bessere Lösung zu finden. Ich bin bereit zu akzeptieren, dass dies genau so ist (dh es gibt keinen geeigneten Weg, um auf 'python2' hinzuweisen, der /usr/bin/pythonportabel und unauffällig ist, ohne viele Änderungen an der Testsuite und am tatsächlichen Framework vorzunehmen).

Avery Chan
quelle
1
Hallo! Nurln -s /usr/bin/python /usr/bin/python2
enedil
In der Tat entwickle ich Git-Multimail unter Linux. Aber ich würde Patches und Tester begrüßen, damit es unter OS X funktioniert. Übrigens, Ihr "python2" -Problem ist jetzt gelöst, da git-multimail sowohl python2 als auch python3 akzeptiert :-).
Matthieu Moy
Der erweiterten Frage fehlt noch ein entscheidendes Detail: Wie sieht die shebang-Zeile in den ausführbaren Skripten aus? Denn git-multimail.pyes ist #!/usr/bin/env python2, so gibt es einen (relativ) einfachen Weg , dies zu tun.
Alexis
@Enedils Kommentar funktionierte jedoch ln -s /usr/bin/python2.7 /usr/local/bin/python2nicht
Phylliida

Antworten:

3

Wenn Sie einen Symlink auflösen (oder untersuchen) müssen, können Sie die plattformunabhängige Bash-Bibliothek 'realpath-lib' verwenden. Standardmäßig emuliert es Readlink und funktioniert unter Mac oder Unix. Es kann auf Github oder Bitbucket gefunden werden und ist kostenlos.

Aber es hört sich so an, als ob Sie nur python2 (anstatt ./python2) aus Ihrem lokalen (Arbeits-) Verzeichnis ausführen möchten. Möglicherweise können Sie dies mit einem Alias ​​in Ihrer .bashrc-Datei tun, oder Sie müssen das Arbeitsverzeichnis (das Ihren Symlink enthält) zu Ihrer PATH-Umgebungsvariablen hinzufügen. Dies kann auch nur für die aktuelle Sitzung oder in der .bashrc-Datei für zukünftige Sitzungen erfolgen. Dies könnte eine Lösung für nur einen bestimmten Benutzer sein.

Eine andere Option, die für alle Benutzer funktionieren würde, wäre, den Symlink python2 zu / usr / bin / python in einem anderen Verzeichnis auf dem Pfad zu erstellen, beispielsweise in / usr / local / bin. Vielleicht so etwas wie:

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

Dann sollte jeder Benutzer oder jedes Skript die Befehle python oder python2 finden. Natürlich erfordert diese Option Administratorrechte (root), um installiert zu werden.

AsymLabs
quelle
Ich habe schließlich aufgegeben. Es gibt zu viele Stellen im Code, die von 'python2' ausgehen, und nicht jede lokalisierte Lösung deckt alle Möglichkeiten ab. Dies ist der am besten geeignete Vorschlaghammer für diesen Nagel.
Avery Chan
@Avery, hast du meine Lösung ausprobiert? Gab es ein Problem? Es wäre nicht erforderlich Sie hinzufügen python2zu /usr/bin(obwohl ich es als eine Verbesserung Ansichten hinzufügen, um ehrlich zu sein).
Alexis
Möglicherweise ist dies mit einem Alias ​​(...) nicht möglich, da der Alias ​​nur die Befehlszeile und keine Skripte beeinflusst. Siehe Wie man die Standardversion von Python in Debian 7.5 ändert?
Piotr Dobrogost
15

Ich glaube, Sie haben mit Apples System zu kämpfen, um mehrere Versionen desselben Programms zu verwalten und zwischen ihnen zu wechseln. Sie können das, was Sie möchten, weniger elegant, aber ohne Probleme mit dem folgenden Skript ausführen python2:

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

Machen Sie es ausführbar ( chmod +x python2) und Sie sind im Geschäft.

Erklärung des Problems:

Wenn Sie es ausführen /usr/bin/python, wird es python2.7 im selben Verzeichnis gefunden und ausgeführt . Ihre symbolische Verknüpfung schlägt fehl, weil das System der symbolischen Verknüpfung folgt /usr/bin, danach sucht und dort nicht python2 findet. Sie können einen Schritt weiter gehen, indem Sie einen "festen Link" anstelle eines symbolischen Links verwenden:

rm python2
ln /usr/bin/python python2

Jetzt gibt es keinen symbolischen Link mehr, nur zwei Dateinamen für dieselbe Datei (Inode). Aber jetzt scheitere ich mit folgender Meldung:

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

Beachten Sie Folgendes python22.7: Das Framework ergänzt 2.7den von Ihnen erstellten Namen! Anstatt zu versuchen, dies zu entwirren und eine Gesamtheit von Links einzurichten, die den Erwartungen entspricht, empfehle ich, dass Sie sich aus dem Versionsverwaltungsframework heraushalten und die oben vorgeschlagene Lösung verwenden.

PS. Möglicherweise gibt es eine bessere Lösung: Wenn Sie zunächst erläutern, was Sie tun müssen (warum Sie python2einen Alias ​​für angeben müssen python), kann Ihnen möglicherweise jemand auf andere Weise dabei helfen. Dies ist als "XY-Problem" in der Umgangssprache Stackexchange bekannt ...

alexis
quelle
Bei der Ausführung /usr/bin/pythonwird python2.7 im selben Verzeichnis gefunden und ausgeführt. Dies ist eine sehr verwirrende Aussage. Wenn Sie den Fall beschreiben, in dem es sich /usr/bin/pythonum einen Symlink handelt, geben Sie dies bitte genauer an.
Piotr Dobrogost
das ist einfach unglaublich schlimm ...
nicolas 30.10.15
Was ist erstaunlich schlimm?
Alexis
2

Versuchen:

ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /usr/local/bin/python2
Liangmin Li
quelle
Ich weiß nicht, warum du Abstimmungen bekommst. Dies ist die einzige Lösung, die für mich funktioniert hat
xApple
1

Mit dem Unix-Befehl können readlinkSie einen physischen Pfad für Links ermitteln.

Beispiele

Angenommen, ich habe den folgenden 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. Um den Wert zu finden, zeigt ein symbolischer Link auf

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

    HINWEIS: Das obige Ergebnis kann ein anderer Link sein. Um dieses Problem zu beheben, lesen Sie # 2 weiter unten.

  2. Um den absoluten Pfad des Wertes herauszufinden, zeigt ein symbolischer Link auf

    $ readlink -f /usr/bin/etags
    /usr/bin/ctags
slm
quelle
0

Ich verstehe nicht - wie kommt es, dass ein Wrapper- Link in Ordnung ist, aber kein Wrapper- Skript ? Beides ist lediglich eine Indirektionsebene. Und müssten Sie Ihre Benutzer nicht noch anweisen, sie nur von einem bestimmten Verzeichnis aus aufzurufen?

In jedem Fall können Sie $PATHnatürlich das aktuelle Arbeitsverzeichnis abrufen:

 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

Bitte holt . aus deinem raus $PATH. Das ist eine schreckliche Idee.

mikeserv
quelle
Warum ist .in meinem $ PATH eine schlechte Idee? Wenn ich es am Ende setze, ist der letzte Ort, der gesucht wird, mein aktuelles Arbeitsverzeichnis (dh `PATH =" $ {PATH}: $ {PWD} ". Ein Wrapper-Skript bedeutet, dass ich es für jede Python-Datei tun werde Ich muss eine zusätzliche Datei erstellen. Ein Wrapper-Link zur ausführbaren Python-Datei stellt nur eine Aufgabe für mich dar.
Avery Chan
@AveryChan Das glaube ich nicht. Ein Wrapper-Skript kann eine Shell-Funktion oder einen Alias ​​mit demselben Namen wie die ausführbare Datei ausgeben. Es kann auch --bind mountdie ausführbare Datei im aktuellen Verzeichnis oder (nur Linux, denke ich) sogar chrootnach Bedarf. Aber . in $PATHfunktioniert für jedes Verzeichnis und ist nicht spezifisch. Dies ist gefährlich für Ihre Benutzer. Auf jeden Fall habe ich oben sehr deutlich gezeigt, wie es geht. Entspricht es nicht Ihren Anforderungen?
mikeserv