¿Cómo obtengo 'realpath' para encontrar mi enlace simbólico?

13

Estoy usando MacOSX bashcomo mi shell. Tengo un enlace simbólico, creado así:

ln -s /usr/bin/python python2 

Tengo un paquete que usa python2 y quiero crear un enlace de símbolo en mi directorio de trabajo actual, /usr/bin/pythonque en realidad es python2. Cuando hago un python2desde la línea de comando me sale este error:

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

Pero invocarlo así ./python2resuelve el camino correctamente. Mi PATHtiene .en ello. De hecho, lo modifiqué, para probarlo, para tenerlo solo ..

¿Cómo resuelvo esto? ¡Gracias!


Contexto

Algunas de las soluciones sugeridas a continuación no funcionarán para mí. Traté de destilar mi pregunta lo más centrada y breve posible para que la gente no se ahogara en un mar de texto, pero claramente necesito proporcionar más antecedentes.

Estoy tratando de desarrollar en un paquete que cloné de git. El paquete original git-multimail, está / fue desarrollado en alguna variante de Linux (supongo que Ubuntu). He estado tratando de modificarlo para poder usarlo y su conjunto de pruebas en MacOSX con la menor modificación posible. He aquí por qué algunas de las soluciones propuestas no son ideales:

  1. Como root, cree un python2enlace simbólico en / usr / bin /. Estoy buscando una solución que no requiera esto. Esta era una opción obvia al principio, pero me gustaría una solución que modifique el sistema host lo menos posible. Es por eso que quería crear un enlace simbólico temporal en el directorio de trabajo actual, agregar el CWD (es decir .) a mi ruta y luego destruirlo cuando haya terminado (es decir, el enlace simbólico).

  2. Cree una secuencia de comandos de contenedor para llamar a la secuencia de comandos de Python con la python existente. El problema con esto es que gran parte del conjunto de pruebas utiliza los archivos de script reales como ejecutables, dependiendo de shebang para encontrar el entorno de ejecución correcto. Esto significaría editar considerablemente el conjunto de pruebas. En este contexto, (vea a continuación un fragmento del marco de prueba), tendría que agregar un contenedor para cada .pyarchivo; Además, el usuario / desarrollador tendría que conocer las diferentes reglas para usar el paquete dependiendo del sistema en el que se encuentren (es decir, en MacOSX asegúrese de no usar los archivos de Python sin invocarlos a través del contenedor o llamar explícitamente /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. Cambiando todas las python2referencias a python. El archivo README sugiere esto, pero esto efectivamente hace que el control de versión sea inútil ya que el sistema ve el cambio como una nueva versión, cuando en realidad no lo es (semánticamente).

He estado usando (3) pero estoy tratando de encontrar una mejor solución. Estoy dispuesto a aceptar que así son las cosas (es decir, no hay una manera adecuada de señalar 'python2' para /usr/bin/pythonque sea portátil y discreto sin muchos cambios en el conjunto de pruebas y el marco real).

Avery Chan
fuente
1
¡Oye! Justln -s /usr/bin/python /usr/bin/python2
enedil
De hecho, desarrollo git-multimail en Linux. Pero me gustaría recibir parches y probadores para que funcione en OS X. Por cierto, su problema "python2" está resuelto ahora, ya que git-multimail acepta python2 y python3 :-).
Matthieu Moy
A la pregunta ampliada aún le falta un detalle crucial: ¿cómo se ve la línea shebang en los scripts ejecutables? Por git-multimail.pylo que es #!/usr/bin/env python2, entonces hay una forma (relativamente) directa de hacer esto.
alexis
El comentario de @ enedil no funcionó, sin embargo lo ln -s /usr/bin/python2.7 /usr/local/bin/python2hizo
Phylliida

Respuestas:

3

Si necesita resolver (o investigar) un enlace simbólico, puede usar la biblioteca bash independiente de la plataforma 'realpath-lib'. Por defecto, emula readlink y funcionará en Mac o Unix. Se puede encontrar en Github o Bitbucket y es gratis.

Pero parece que solo quieres hacer python2 (en lugar de ./python2) desde tu directorio local (de trabajo). Es posible hacer esto con un alias en su .bashrc o de lo contrario necesitará agregar el directorio de trabajo (que contiene su enlace simbólico) a su variable de entorno PATH. Esto también se puede hacer solo para la sesión actual o dentro del archivo .bashrc para futuras sesiones. Esto podría ser una solución solo para un usuario específico.

Otra opción que funcionaría para todos los usuarios sería crear el enlace simbólico python2 a / usr / bin / python en otro directorio en la ruta, digamos en / usr / local / bin. Quizás algo como:

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

Luego, cualquier usuario o script debe encontrar los comandos python o python2. Por supuesto, esta opción requiere privilegios de administrador (root) para instalar.

AsymLabs
fuente
Finalmente me rendí. Hay demasiados lugares que asumen 'python2' en el código y no todas las soluciones localizadas cubren todas las posibilidades. Este es el mazo más apropiado para esta uña.
Avery Chan
@Avery, ¿intentaste mi solución? ¿Hubo un problema? No te habría requerido para agregar python2a /usr/bin(aunque vista de añadirlo como una mejora, para ser honesto).
alexis
Es posible hacer esto con un alias (...) No es posible ya que el alias influye solo en la línea de comandos y no en los scripts. Consulte ¿Cómo cambiar la versión predeterminada de Python en Debian 7.5?
Piotr Dobrogost
15

Creo que estás en conflicto con el sistema de Apple para administrar y cambiar entre múltiples versiones del mismo programa. Puede lograr lo que quiere, con menos elegancia pero sin problemas, con el siguiente script llamado python2:

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

Hazlo ejecutable ( chmod +x python2) y estarás en el negocio.

Explicación del problema:

Cuando ejecuta /usr/bin/python, encuentra y se ejecuta python2.7 en el mismo directorio. Su enlace simbólico falla porque el sistema sigue el enlace simbólico a /usr/bin, luego busca y no encuentra python2 allí. Puede ir un paso más allá utilizando un "enlace duro" en lugar de un enlace simbólico:

rm python2
ln /usr/bin/python python2

Ahora no hay un enlace simbólico a seguir, solo dos nombres de archivo para el mismo archivo (inodo). Pero ahora fallo con el siguiente mensaje:

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

Observe lo siguiente python22.7: ¡El marco se agrega 2.7al nombre que ha creado! En lugar de tratar de desentrañar esto y configurar un bosque de enlaces que coincida con sus expectativas, le recomiendo que se mantenga alejado del marco de administración de versiones y utilice la solución sugerida anteriormente.

PD. Puede haber una solución mejor: si para empezar explicaras lo que necesitas hacer (por qué necesitas proporcionar python2un alias python), alguien probablemente pueda ayudarte a hacerlo de una manera diferente. Esto se conoce como un "problema XY" en la jerga de stackexchange ...

alexis
fuente
Cuando ejecuta /usr/bin/python, encuentra y ejecuta python2.7 en el mismo directorio. Esta es una declaración muy confusa. Si describe el caso donde /usr/bin/pythonhay un enlace simbólico, por favor sea más específico.
Piotr Dobrogost
eso es increíblemente malo ..
nicolas
¿Qué es asombrosamente malo?
alexis
2

Tratar:

ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /usr/local/bin/python2
Liangmin Li
fuente
No sé por qué
recibes votos negativos
1

Puede usar el comando Unix readlinkpara encontrar una ruta física de enlaces.

Ejemplos

Digamos que tengo el siguiente enlace:

$ 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. Para encontrar el valor, un enlace simbólico apunta a

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

    NOTA: El resultado anterior puede ser otro enlace. Para resolver esto, vea el # 2 a continuación.

  2. Para descubrir la ruta absoluta del valor, un enlace simbólico apunta a

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

No entiendo, ¿cómo es que crees que un enlace de contenedor está bien, pero no un script de contenedor ? Cualquiera de los dos es simplemente un nivel de indirección. ¿Y no tendrías que instruir a tus usuarios solo para que lo llamen desde cierto directorio?

En cualquier caso, puede obtener el directorio de trabajo actual, por $PATHsupuesto:

 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

Por favor, consigue. fuera de su $PATH. Esa es una idea horrible.

mikeserv
fuente
¿Por qué .en mi $ PATH es una mala idea? Si lo pongo al final, entonces el último lugar que se buscará es mi directorio de trabajo actual (es decir, `PATH =" $ {PATH}: $ {PWD} ". Un script de envoltura significa que por cada archivo de Python voy a tengo que crear un archivo adicional. Un enlace de envoltura al ejecutable de Python solo crea una cosa para mí.
Avery Chan
@AveryChan No lo creo. Una secuencia de comandos de contenedor puede generar una función de shell o un alias que tenga el mismo nombre que el ejecutable. También puede --bind mountejecutar el archivo ejecutable en el directorio actual o (solo Linux, supongo) incluso chrootsi es necesario. Pero . en $PATHtrabajos para cualquier directorio y no es específico. Esto es peligroso para tus usuarios. En cualquier caso, demostré muy claramente cómo hacerlo arriba. ¿No cumple con sus requisitos?
mikeserv