Search code examples
bashcommand-line-interfacels

How to follow symlinks for which output?


I have this handy function for showing symlinks from the which command.

function whichl() {
    ls -la $(which -a $@)
}

It works great for things that are symlinked from the path, like python.

$ whichl python
-rwxr-xr-x  1 root  wheel  66880 Mar 27 23:02 /usr/bin/python
lrwxr-xr-x  1 me    admin     43 Dec 19  2017 /usr/local/bin/python -> /usr/local/Cellar/python/2.7.14/bin/python2

$ ls -la $(which -a python3)
lrwxr-xr-x  1 me    admin  34 Jun  8 10:42 /usr/local/bin/python3 -> ../Cellar/python/3.6.5/bin/python3

It does not work so great when which doesn't find anything; the ls -la command runs against the current directory. This has confused me for the last time!

So, looking for two answers here.

  1. Is there a better way to get which results to show symlinks?
    I'm on OS X (if it wasn't obvious) and man which says my version is BSD December 13, 2006.

  2. What is the best way to get my helper function to halt on when which returns no results? I've confirmed the return code in this case is 1, but a simple set -e doesn't change the behavior.


Solution

  • As I mentioned in the question, this doesn't work:

    function whichl() {
        set -e
        ls -la $(which -a $@)
    }
    

    The explanation from the comments:

    You call set -e in the current shell (where the function runs) but which is executed in a subshell (because of $(...)). You can store the value produced by $(which -a $@) in a variable and run ls -la only when it is not empty.

    Following that suggestion, this is what I arrived at.

    function whichl() {
        RESULT=$(which -a $@)
        if [ -z "$RESULT" ]; then
            echo "No results for \"$@\""
            return 1
        fi
        ls -la -- ${RESULT}
    }
    

    And it works perfectly from all I can test right now!

    $ whichl python python3
    -rwxr-xr-x  1 root  wheel  66880 Mar 27 23:02 /usr/bin/python
    lrwxr-xr-x  1 me    admin     43 Dec 19  2017 /usr/local/bin/python -> /usr/local/Cellar/python/2.7.14/bin/python2
    lrwxr-xr-x  1 me    admin     34 Jun  8 10:42 /usr/local/bin/python3 -> ../Cellar/python/3.6.5/bin/python3
    

    Notice it returns 3 results from 2 inputs, the system python and brew python.

    $ whichl foo bar
    No results for "foo bar"