Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am on MacOSX using bash as my shell. I have symbolic link, created like this:

ln -s /usr/bin/python python2 

I have a package that uses python2 and I want to create a symbol link in my current working directory to /usr/bin/python which is actually python2. When I do a python2 from the command line I get this error:

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

But invoking it like this ./python2 resolves the path correctly. My PATH has . in it. In fact I modified it, for testing, to only have . in it.

How do I resolve this? Thanks!


Context

A number of the suggested solutions below won't work for me. I tried to distill my question as focused and brief as possible so that people wouldn't drown in a sea of text, but clearly I need to provide more background.

I'm trying to do develop on a package that I cloned from git. The original package, git-multimail, is/was developed on some variant of Linux (I'm guessing Ubuntu). I've been trying to modify it to be able to use it and its test suite on MacOSX with as little modification as possible. Here's why some of the proposed solutions aren't ideal:

  1. As root, create a python2 symlink in /usr/bin/. I'm looking for a solution that wouldn't require this. This was an obvious option at the beginning, but I'd like a solution that modifies the host system as little as possible. This is why I wanted to create a temporary symlink in the current working directory, add the CWD (i.e. .) to my path, and then destroy this when finished (i.e. the symlink).

  2. Create a wrapper script to call the python script with the existing python. The problem with this is that much of the test suite uses the actual script_files as executables, depending on shebang to find the correct execution environment. This would mean editing the test suite considerably. In this context, (see below for a snippet of the test-framework), I would have to add a wrapper for every .py file; further the user/developer would have to be aware of different rules for using the package depending on what system they are on (i.e. on MacOSX make sure you don't use the python files without invoking them via the wrapper or explicitly calling /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. Changing all python2 references to python. The README suggests this, but this effectively makes version control useless since the system sees the change as new version, when in fact it's not (semantically).

I've been using (3) but I'm trying to find a better solution. I'm willing to accept that this is just the way things are (i.e. there's not a suitable way to point 'python2' to /usr/bin/python that is portable and unobtrusive without a lot of changes to the test suite and actual framework).

share|improve this question
    
Hey! Just ln -s /usr/bin/python /usr/bin/python2 –  enedil Apr 25 at 22:37

4 Answers 4

up vote 1 down vote accepted

If you need to resolve (or investigate) a symlink you can use the platform independent bash library 'realpath-lib'. By default it emulates readlink and will work on Mac or Unix. It can be found on Github or Bitbucket and it's free.

But it sounds like you want to just do python2 (rather than ./python2) from your local (working) directory. It might be possible to do this with an alias in your .bashrc or otherwise you will need to add the working directory (that contains your symlink) to your PATH environment variable. This can also be done for the current session only or within the .bashrc file for future sessions. This could be a solution for just a specific user.

Another option that would work for all users would be to create the python2 symlink to /usr/bin/python in another directory on the path, say in /usr/local/bin. Perhaps something like:

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

Then any user or script should find the python or python2 commands. Of course this option requires admin (root) privileges to install.

share|improve this answer
    
I eventually gave up. There are too many places which assume 'python2' in the code and not every localized solution covers all the possibilities. This is the most appropriate sledgehammer for this nail. –  Avery Chan May 5 at 6:38
    
@Avery, did you try my solution? Was there a problem? It wouldn't have required you to add python2 to /usr/bin (though I view adding it as an improvement, to be honest). –  alexis May 28 at 8:12
    
It might be possible to do this with an alias (...) It's not possible as alias influences only command line and not scripts. See How to change the default version of Python in Debian 7.5? –  Piotr Dobrogost Jul 10 at 7:44

You can use the Unix command readlink to find out a links physical path.

Examples

Say I have the following 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. To find the value a symbolic link points to

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

    NOTE: The above result may be another link. To resolve this see #2 below.

  2. To find out the absolute path of the value a symbolic link points to

    $ readlink -f /usr/bin/etags
    /usr/bin/ctags
    
share|improve this answer

I believe you're running afoul of Apple's system for managing and switching among multiple versions of the same program. You can accomplish what you want, less elegantly but without problems, with the following script named python2:

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

Make it executable (chmod +x python2), and you're in business.

Explanation of the problem:

When you run /usr/bin/python, it finds and executes python2.7 in the same directory. Your symbolic link fails because the system follows the symlink to /usr/bin, then looks for and fails to find python2 there. You can get one step further by using a "hard link" instead of a symbolic link:

rm python2
ln /usr/bin/python python2

Now there's no symbolic link to follow, just two filenames for the same file (inode). But now I fail with the following message:

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

Notice the python22.7: The framework is adding 2.7 to the name you've created! Instead of trying to unravel this and set up a forest of links that matches its expectations, I recommend you stay out of the way of the version management framework, and use the solution suggested above.

PS. There might be a better solution: If you would explain what you needed to do to begin with (why do you need to provide python2 as an alias for python), someone can probably help you do it in a different way. This is known as an "XY problem" in stackexchange lingo...

share|improve this answer
    
When you run /usr/bin/python, it finds and executes python2.7 in the same directory. This is very confusing statement. If you describe the case where /usr/bin/python is a symlink then please be more specific. –  Piotr Dobrogost Jul 10 at 7:41

I don't understand - how is it you believe a wrapper link is ok, but not a wrapper script? Either one is merely level of indirection. And wouldn't you still have to instruct your users only to call it from a certain directory?

In any case, you can get the current working directory in $PATH of course:

 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

Please, get . out of your $PATH. That's a horrible idea.

share|improve this answer
    
Why is . in my $PATH a bad idea? If I put it at the end, then the last place that will be looked is my current working directory (i.e. ` PATH="${PATH}:${PWD}". A wrapper script means that for every python file I'll have to create an additional file. A wrapper link to the python executable just creates one thing for me to do. –  Avery Chan Apr 28 at 5:00
    
@AveryChan I don't think so. A wrapper script can source a shell function or alias that with the same name as the executable. It can also --bind mount the executable in the current directory or (linux only, I guess) even chroot as necessary. But . in $PATH works for any directory and is not specific. This is dangerous for your users. In any case, I very clearly demonstrated how to do it above. Does it not meet your requirements? –  mikeserv Apr 28 at 5:08

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.