2

Whenever I use which I do this: $ which -a npm

Which results in: /usr/local/bin/npm

Then to find the real path, I run: ls -l /usr/local/bin/npm

I would like a fast way of doing this. The best I have come up with is defining a function:

which(){
  /usr/bin/which -a "$@" | xargs ls -l | tr -s ' ' | cut -d ' ' -f 9-
}

Now it has a nice output of: /usr/local/bin/npm -> ../lib/node_modules/npm/bin/npm-cli.js

Is there a better way to do this? I don't like using cut like this.

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Michael Ozeryansky
  • 7,204
  • 4
  • 49
  • 61

2 Answers2

0

This won't print the -> output ls -l does, but it will resolve symlinks:

which() {
    command which -a "$@" | xargs -d '\n' readlink -m
}

If you want the -> output but want to do it more robustly, you could mimic ls -l with:

which() {
    command which -a "$@" | while IFS= read -r file; do
        if [[ -L $file ]]; then
            echo "$file -> $(readlink -m "$file")"
        else
            echo "$file"
        fi
    done
}

What does command do?

command suppresses function lookup and runs the built-in which command as if which() weren't defined. This way you don't have to hardcode /usr/bin/which.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
0

awk: if first character is "l" (link), print fields 9,10,11; else only 9.

[ranga@garuda ~]$ ls -l $(which -a firefox)|awk '{print $1 ~ /^l/ ? $9 $10 $11 : $9 }'
/usr/bin/firefox->/usr/lib64/firefox/firefox
  • $1 is the first field
  • $1 ~ /^l/ ? tests whether the first field matches the pattern ^l (first character is "l")
  • if the test passes, print receives $9 $10 $11; else, only $9.

sed : remove first 8 non-space and space character bunches.

[ranga@garuda ~]$ ls -l $(which firefox) | sed 's/^\([^ ]*[ ]*\)\{8\}//'
/usr/bin/firefox -> /usr/lib/firefox/firefox
  • [ ]* matches a bunch of contiguous spaces
  • [^ ]* matches a contiguous bunch of non-space characters
  • the grouping \([^ ]*[ ]*\) matches a text with one non-space bunch and one space bunch (in that order).
  • \{8\} matches 8 contiguous instances of this combination. ^ at the beginning pins the match to the beginning of the line.
  • 's/^\([^ ]*[ ]*\)\{8\}//' replaces a match with empty text - effectively removing it.

seems to work so long as you aren't running "which" on an alias.

these commands are not presented inside a function but can be used in one (which you already know how to).

ranga
  • 372
  • 1
  • 4