For many years I've been irritated by Linux's symbolic links - particularly the
useful but incredibly annoying /etc/alternatives/ arrangement. This is
meant to allow different packages to install the same binaries - not usually at
the same time, but /etc/alternatives/java
is meant to be a link to
whichever version of Java you have installed. A reasonably good idea, but the
problem is this:
$ which java
/usr/bin/java
$ ls -l /usr/bin/java
lrwxrwxrwx. 1 root root 22 Dec 6 2020 /usr/bin/java -> /etc/alternatives/java
The problem is ... you still don't know which java
you have. You have to
go 'round again:
$ ls -l /etc/alternatives/java
lrwxrwxrwx. 1 root root 63 May 17 09:33 /etc/alternatives/java -> /usr/lib/jvm/java-11-openjdk-11.0.11.0.9-2.fc33.x86_64/bin/java
As it turns out, this is the actual binary - but in this context you can't actually tell (it could be another link). There are better ways to check, in the form of a couple utilities: namei
and readlink
. The former provides more information, but most of the time I just want the final binary target, and the latter is better for that.
$ namei $(which java)
f: /usr/bin/java
d /
d usr
d bin
l java -> /etc/alternatives/java
d /
d etc
d alternatives
l java -> /usr/lib/jvm/java-11-openjdk-11.0.11.0.9-2.fc33.x86_64/bin/java
d /
d usr
d lib
d jvm
d java-11-openjdk-11.0.11.0.9-2.fc33.x86_64
d bin
- java
I'm not trying to give you a full description of these things: read the (short) man pages if you want the full details. But namei
traces the links back to their origin, telling you when it finds a f file, d directory, or l link. readlink
defaults to only disambiguating the first link: to get it to follow all further links, use the -f option. For Mac users, Darwin has readlink
but it is itself a link to stat
and doesn't support -f. If you want that, brew install coreutils
and use the greadlink
command ("g" for "GNU").
$ readlink -f $(which java)
/usr/lib/jvm/java-11-openjdk-11.0.11.0.9-2.fc33.x86_64/bin/java
I use this command a LOT, including assigning its output to a variable to capture the target binary.