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!


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)
    cd $TESTREPO
    test_email() {
        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).

  • 1
    Hey! Just ln -s /usr/bin/python /usr/bin/python2 – enedil Apr 25 '14 at 22:37
  • Indeed I develop git-multimail on Linux. But I'd welcome patches and testers to make it work on OS X. BTW, your "python2" issue is solved now, as git-multimail accepts both python2 and python3 :-). – Matthieu Moy May 14 '16 at 21:01
  • The expanded question is still missing a crucial detail: What does the shebang line in the executable scripts look like? For git-multimail.py it is #!/usr/bin/env python2, so there's a (relatively) straightforward way to do this. – alexis Dec 13 '16 at 22:31
  • @enedil's comment didn't work, however ln -s /usr/bin/python2.7 /usr/local/bin/python2 did – Phylliida Feb 14 '18 at 20:54

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.

  • 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 '14 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 '14 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 '14 at 7:44

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:

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...

  • 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 '14 at 7:41
  • that's just amazingly bad.. – nicolas Oct 30 '15 at 15:30
  • What is amazingly bad? – alexis Oct 30 '15 at 18:07


ln -s /System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /usr/local/bin/python2
  • Don't know why you are getting downvotes, this is the only solution that worked for me – xApple Apr 12 at 19:50

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


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

    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

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 

 Hi! I'm python

 rm python 
 python -V 
 ln -s /usr/bin/python2 ./python 
 python -V

 Python 3.4.0
 Python 2.7.6

 python -V

 Python 3.4.0

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

  • 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 '14 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 '14 at 5:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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