Como obtenho 'caminho real' para encontrar meu link simbólico?

13

Estou no MacOSX usando bashcomo shell. Eu tenho um link simbólico, criado assim:

ln -s /usr/bin/python python2 

Eu tenho um pacote que usa python2 e quero criar um link de símbolo no meu diretório de trabalho atual para o /usr/bin/pythonqual é realmente python2. Quando eu faço um a python2partir da linha de comando, recebo este erro:

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

Mas invocá-lo assim ./python2resolve o caminho corretamente. Meu PATHtem .nele. Na verdade, eu o modifiquei, para teste, para ter apenas .nele.

Como eu resolvo isso? Obrigado!


Contexto

Várias das soluções sugeridas abaixo não funcionarão para mim. Tentei destilar minha pergunta o mais focada e breve possível, para que as pessoas não se afogassem em um mar de texto, mas claramente eu preciso fornecer mais informações.

Estou tentando desenvolver um pacote que eu clonei do git. O pacote original,, git-multimailé / foi desenvolvido em alguma variante do Linux (eu acho que o Ubuntu). Eu tenho tentado modificá-lo para poder usá-lo e sua suíte de testes no MacOSX com a menor modificação possível. Eis por que algumas das soluções propostas não são ideais:

  1. Como root, crie um python2link simbólico em / usr / bin /. Estou procurando uma solução que não exija isso. Essa era uma opção óbvia no começo, mas eu gostaria de uma solução que modifique o sistema host o menos possível. É por isso que eu queria criar um link simbólico temporário no diretório de trabalho atual, adicionar o CWD (ou seja .) ao meu caminho e destruí-lo quando terminar (ou seja, o link simbólico).

  2. Crie um script de wrapper para chamar o script python com o python existente. O problema disso é que grande parte do conjunto de testes usa os arquivos de script reais como executáveis, dependendo do shebang para encontrar o ambiente de execução correto. Isso significaria editar o conjunto de testes consideravelmente. Nesse contexto (veja abaixo um trecho da estrutura de teste), eu precisaria adicionar um wrapper para cada .pyarquivo; além disso, o usuário / desenvolvedor teria que estar ciente de regras diferentes para usar o pacote, dependendo do sistema em que está (por exemplo, no MacOSX, verifique se você não usa os arquivos python sem invocá-los através do wrapper ou chamar explicitamente /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. Alterando todas as python2referências para python. O README sugere isso, mas isso efetivamente torna o controle de versão inútil, pois o sistema vê a alteração como nova versão, quando na verdade não é (semanticamente).

Estou usando (3), mas estou tentando encontrar uma solução melhor. Estou disposto a aceitar que é assim que as coisas são (ou seja, não há uma maneira adequada de apontar 'python2' para /usr/bin/pythonisso é portátil e discreto, sem muitas alterações no conjunto de testes e na estrutura real).

Avery Chan
fonte
1
Ei! Apenasln -s /usr/bin/python /usr/bin/python2
enedil
Na verdade, desenvolvo o git-multimail no Linux. Mas gostaria de receber patches e testadores para fazê-lo funcionar no OS X. BTW, seu problema "python2" está resolvido agora, já que o git-multimail aceita python2 e python3 :-).
Matthieu Moy 14/05
A questão expandida ainda está sem um detalhe crucial: como é a linha shebang nos scripts executáveis? Pois git-multimail.pyé #!/usr/bin/env python2, então existe uma maneira (relativamente) direta de fazer isso.
alexis
@ comentário de enedil não funcionou, no entanto ln -s /usr/bin/python2.7 /usr/local/bin/python2fez
Phylliida

Respostas:

3

Se você precisar resolver (ou investigar) um link simbólico, poderá usar a biblioteca bash independente da plataforma 'realpath-lib'. Por padrão, ele emula o readlink e funciona no Mac ou no Unix. Pode ser encontrado no Github ou Bitbucket e é gratuito.

Mas parece que você deseja apenas executar python2 (em vez de ./python2) no diretório local (de trabalho). Pode ser possível fazer isso com um alias no seu .bashrc ou você precisará adicionar o diretório de trabalho (que contém seu link simbólico) à sua variável de ambiente PATH. Isso também pode ser feito apenas para a sessão atual ou no arquivo .bashrc para sessões futuras. Esta poderia ser uma solução para apenas um usuário específico.

Outra opção que funcionaria para todos os usuários seria criar o link simbólico python2 para / usr / bin / python em outro diretório no caminho, digamos em / usr / local / bin. Talvez algo como:

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

Qualquer usuário ou script deve encontrar os comandos python ou python2. Obviamente, esta opção requer privilégios de administrador (root) para instalar.

AsymLabs
fonte
Eu finalmente desisti. Existem muitos lugares que assumem 'python2' no código e nem toda solução localizada cobre todas as possibilidades. Esta é a marreta mais adequada para esta unha.
Avery Chan
@Avery, você tentou minha solução? Houve algum problema? Não teria exigido que você adicione python2a /usr/bin(embora I Vista adicioná-lo como uma melhoria, para ser honesto).
Alexis 28/05
Pode ser possível fazer isso com um alias (...) Não é possível, pois o alias influencia apenas a linha de comando e não os scripts. Veja Como mudar a versão padrão do Python no Debian 7.5?
Piotr Dobrogost
15

Acredito que você esteja com problemas no sistema da Apple para gerenciar e alternar entre várias versões do mesmo programa. Você pode realizar o que deseja, com menos elegância, mas sem problemas, com o seguinte script chamado python2:

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

Torne-o executável ( chmod +x python2) e você estará no negócio.

Explicação do problema:

Quando você executa /usr/bin/python, ele localiza e executa python2.7 no mesmo diretório. Seu link simbólico falha porque o sistema segue o link simbólico para /usr/bin, depois procura e falha ao encontrá python2 -lo. Você pode dar um passo adiante usando um "link físico" em vez de um link simbólico:

rm python2
ln /usr/bin/python python2

Agora não há link simbólico a seguir, apenas dois nomes de arquivos para o mesmo arquivo (inode). Mas agora falho com a seguinte mensagem:

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

Observe o python22.7: A estrutura está adicionando 2.7ao nome que você criou! Em vez de tentar desvendar isso e configurar uma floresta de links que atenda às suas expectativas, recomendo que você fique fora do caminho da estrutura de gerenciamento de versões e use a solução sugerida acima.

PS. Pode haver uma solução melhor: se você explicasse o que precisava fazer para começar (por que você precisa fornecer python2um apelido para python), alguém provavelmente poderá ajudá-lo a fazê-lo de uma maneira diferente. Isso é conhecido como um "problema XY" no jargão stackexchange ...

alexis
fonte
Quando você executa /usr/bin/python, ele localiza e executa python2.7 no mesmo diretório. Esta é uma afirmação muito confusa. Se você descrever o caso em que /usr/bin/pythonhá um link simbólico, seja mais específico.
Piotr Dobrogost
isso é incrivelmente ruim ..
nicolas
O que é incrivelmente ruim?
Alexis30 /
2

Experimentar:

ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /usr/local/bin/python2
Liangmin Li
fonte
Não sei por que você está recebendo downvotes, esta é a única solução que funcionou para mim
xApple
1

Você pode usar o comando Unix readlinkpara descobrir o caminho físico dos links.

Exemplos

Digamos que tenho o seguinte 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. Para encontrar o valor que um link simbólico aponta para

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

    NOTA: O resultado acima pode ser outro link. Para resolver isso, consulte o item 2 abaixo.

  2. Para descobrir o caminho absoluto do valor, um link simbólico aponta para

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

Eu não entendo - como você acredita que um link de wrapper está correto, mas não um script de wrapper ? Qualquer um é apenas o nível de indireção. E você ainda não teria que instruir seus usuários para chamá-lo de um determinado diretório?

De qualquer forma, é possível obter o diretório de trabalho atual $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

Por favor, pegue. fora do seu $PATH. Essa é uma ideia horrível.

mikeserv
fonte
Por que .no meu $ PATH é uma má ideia? Se eu colocar no final, o último local que será procurado é o meu diretório de trabalho atual (por exemplo, `PATH =" $ {PATH}: $ {PWD} ". Um script de wrapper significa que, para cada arquivo python, eu vou tem que criar um arquivo adicional a. link de invólucro para o executável python apenas cria uma coisa para eu fazer.
Avery Chan
@AveryChan, acho que não. Um script de wrapper pode originar uma função shell ou alias com o mesmo nome que o executável. Também pode ser --bind mountexecutável no diretório atual ou (apenas no Linux, eu acho), mesmo chrootque seja necessário. Mas . em $PATHobras para qualquer diretório e não é específico. Isso é perigoso para seus usuários. De qualquer forma, demonstrei claramente como fazê-lo acima. Não atende aos seus requisitos?
mikeserv