Comment obtenir «realpath» pour trouver mon lien symbolique?


13

Je suis sur MacOSX en utilisant bashmon shell. J'ai un lien symbolique, créé comme ceci:

ln -s /usr/bin/python python2 

J'ai un paquet qui utilise python2 et je veux créer un lien de symbole dans mon répertoire de travail actuel vers /usr/bin/pythonlequel est en fait python2. Lorsque je fais un à python2partir de la ligne de commande, j'obtiens cette erreur:

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

Mais l'invoquer comme ça ./python2résout le chemin correctement. Mon PATHa .dedans. En fait je l'ai modifié, pour le tester, pour ne l'avoir .qu'en lui.

Comment résoudre ça? Merci!


Le contexte

Un certain nombre des solutions suggérées ci-dessous ne fonctionneront pas pour moi. J'ai essayé de distiller ma question de la manière la plus ciblée et la plus brève possible afin que les gens ne se noient pas dans une mer de texte, mais je dois clairement fournir plus d'informations.

J'essaie de développer sur un package que j'ai cloné depuis git. Le package d'origine,, git-multimailest / a été développé sur une variante de Linux (je suppose Ubuntu). J'ai essayé de le modifier pour pouvoir l'utiliser et sa suite de tests sur MacOSX avec le moins de modifications possible. Voici pourquoi certaines des solutions proposées ne sont pas idéales:

  1. En tant que root, créez un python2lien symbolique dans / usr / bin /. Je cherche une solution qui n'exigerait pas cela. C'était une option évidente au début, mais j'aimerais une solution qui modifie le moins possible le système hôte. C'est pourquoi je voulais créer un lien symbolique temporaire dans le répertoire de travail actuel, ajouter le CWD (ie .) à mon chemin, puis le détruire une fois terminé (ie le lien symbolique).

  2. Créez un script wrapper pour appeler le script python avec le python existant. Le problème avec cela est qu'une grande partie de la suite de tests utilise les fichiers de script réels comme exécutables, selon shebang pour trouver l'environnement d'exécution correct. Cela impliquerait de modifier considérablement la suite de tests. Dans ce contexte, (voir ci-dessous pour un extrait du cadre de test), je devrais ajouter un wrapper pour chaque .pyfichier; en outre, l'utilisateur / développeur devrait être conscient des différentes règles d'utilisation du package selon le système sur lequel il se trouve (c'est-à-dire sur MacOSX, assurez-vous de ne pas utiliser les fichiers python sans les appeler via le wrapper ou appeler explicitement /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. Changer toutes les python2références à python. Le README le suggère, mais cela rend le contrôle de version inutile car le système voit le changement comme une nouvelle version, alors qu'en fait ce n'est pas (sémantique).

J'utilise (3) mais j'essaie de trouver une meilleure solution. Je suis prêt à accepter que c'est juste ainsi que les choses sont (c'est-à-dire qu'il n'y a pas de moyen approprié de pointer «python2» vers ce /usr/bin/pythonqui est portable et discret sans beaucoup de changements dans la suite de tests et le cadre réel).


1
Hey! Justln -s /usr/bin/python /usr/bin/python2
enedil

En effet je développe git-multimail sous Linux. Mais j'accueillerais volontiers les correctifs et les testeurs pour le faire fonctionner sur OS X. BTW, votre problème "python2" est maintenant résolu, car git-multimail accepte à la fois python2 et python3 :-).
Matthieu Moy

Il manque encore un détail crucial à la question développée: à quoi ressemble la ligne shebang dans les scripts exécutables? Car git-multimail.pyc'est le cas #!/usr/bin/env python2, il existe donc un moyen (relativement) simple de le faire.
alexis

@ commentaire de enedil n'a pas fonctionné, mais a ln -s /usr/bin/python2.7 /usr/local/bin/python2fait
Phylliida

Réponses:


3

Si vous avez besoin de résoudre (ou d'étudier) un lien symbolique, vous pouvez utiliser la bibliothèque bash indépendante de la plateforme 'realpath-lib'. Par défaut, il émule le lien de lecture et fonctionnera sur Mac ou Unix. Il peut être trouvé sur Github ou Bitbucket et c'est gratuit.

Mais il semble que vous souhaitiez simplement faire python2 (plutôt que ./python2) à partir de votre répertoire local (de travail). Il peut être possible de le faire avec un alias dans votre .bashrc ou sinon vous devrez ajouter le répertoire de travail (qui contient votre lien symbolique) à votre variable d'environnement PATH. Cela peut également être effectué pour la session en cours uniquement ou dans le fichier .bashrc pour les sessions futures. Cela pourrait être une solution pour un utilisateur spécifique.

Une autre option qui fonctionnerait pour tous les utilisateurs serait de créer le lien symbolique python2 vers / usr / bin / python dans un autre répertoire du chemin, par exemple dans / usr / local / bin. Peut-être quelque chose comme:

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

Ensuite, tout utilisateur ou script devrait trouver les commandes python ou python2. Bien sûr, cette option nécessite des privilèges d'administrateur (root) pour l'installation.


J'ai finalement abandonné. Il y a trop d'endroits qui supposent «python2» dans le code et toutes les solutions localisées ne couvrent pas toutes les possibilités. C'est le marteau le plus approprié pour cet ongle.
Avery Chan

@Avery, avez-vous essayé ma solution? Y avait-il un problème? Cela n'aurait pas exigé que vous ajoutiez python2à /usr/bin(même si je considère l'ajout comme une amélioration, pour être honnête).
alexis

Il pourrait être possible de le faire avec un alias (...) Ce n'est pas possible car l'alias n'influence que la ligne de commande et non les scripts. Voir Comment changer la version par défaut de Python dans Debian 7.5?
Piotr Dobrogost le

15

Je crois que vous ne respectez pas le système d'Apple pour gérer et basculer entre plusieurs versions du même programme. Vous pouvez accomplir ce que vous voulez, de manière moins élégante mais sans problème, avec le script suivant nommé python2:

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

Rendez-le exécutable ( chmod +x python2), et vous êtes en affaires.

Explication du problème:

Lorsque vous exécutez /usr/bin/python, il trouve et s'exécute python2.7 dans le même répertoire. Votre lien symbolique échoue car le système suit le lien symbolique vers /usr/bin, puis le recherche et n'y parvient pas python2 . Vous pouvez aller plus loin en utilisant un "lien dur" au lieu d'un lien symbolique:

rm python2
ln /usr/bin/python python2

Maintenant, il n'y a plus de lien symbolique à suivre, juste deux noms de fichiers pour le même fichier (inode). Mais maintenant j'échoue avec le message suivant:

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

Remarquez le python22.7: Le cadre ajoute 2.7au nom que vous avez créé! Au lieu d'essayer de résoudre ce problème et de configurer une forêt de liens correspondant à ses attentes, je vous recommande de rester à l'écart du cadre de gestion des versions et d'utiliser la solution suggérée ci-dessus.

PS. Il pourrait y avoir une meilleure solution: si vous expliquez ce que vous devez faire pour commencer (pourquoi devez-vous fournir python2un alias python), quelqu'un peut probablement vous aider à le faire d'une manière différente. Ceci est connu comme un "problème XY" dans le jargon stackexchange ...


Lorsque vous exécutez /usr/bin/python, il trouve et exécute python2.7 dans le même répertoire. C'est une déclaration très déroutante. Si vous décrivez le cas où se /usr/bin/pythontrouve un lien symbolique, veuillez être plus précis.
Piotr Dobrogost le

c'est juste incroyablement mauvais ..
nicolas

Qu'est-ce qui est incroyablement mauvais?
alexis

2

Essayer:

ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /usr/local/bin/python2

Je ne sais pas pourquoi vous obtenez des votes négatifs, c'est la seule solution qui a fonctionné pour moi
xApple

1

Vous pouvez utiliser la commande Unix readlinkpour trouver un chemin physique de liens.

Exemples

Disons que j'ai le lien suivant:

$ 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. Pour trouver la valeur vers laquelle un lien symbolique pointe

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

    REMARQUE: le résultat ci-dessus peut être un autre lien. Pour résoudre ce problème, voir n ° 2 ci-dessous.

  2. Pour connaître le chemin absolu de la valeur vers laquelle un lien symbolique pointe

    $ readlink -f /usr/bin/etags
    /usr/bin/ctags

0

Je ne comprends pas - comment pensez-vous qu'un lien wrapper est ok, mais pas un script wrapper ? L'un ou l'autre n'est qu'un niveau d'indirection. Et ne seriez-vous pas obligé de demander à vos utilisateurs de l'appeler uniquement à partir d'un certain répertoire?

Dans tous les cas, vous pouvez $PATHbien sûr obtenir le répertoire de travail actuel :

 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

Je vous en prie. hors de votre $PATH. C'est une horrible idée.


Pourquoi .dans mon $ PATH une mauvaise idée? Si je le mets à la fin, alors le dernier endroit qui sera regardé est mon répertoire de travail actuel (ie `PATH =" $ {PATH}: $ {PWD} ". Un script wrapper signifie que pour chaque fichier python je vais devez créer un fichier supplémentaire. Un lien wrapper vers l'exécutable python ne fait que créer une chose pour moi
Avery Chan

@AveryChan Je ne pense pas. Un script wrapper peut générer une fonction shell ou un alias portant le même nom que l'exécutable. Il peut également être --bind mountexécutable dans le répertoire courant ou (Linux uniquement, je suppose) même chrootsi nécessaire. Mais . en $PATHtravaux pour n'importe quel répertoire et n'est pas spécifique. C'est dangereux pour vos utilisateurs. En tout cas, j'ai très clairement démontré comment le faire ci-dessus. Ne répond-il pas à vos exigences?
mikeserv
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.