For use in a shell-script, I’m looking for a commandline-way to get the destination of a symbolic link. The closest I’ve come so far is stat -N src, which outputs src -> dst. Of course I could parse the output and get dst, but I wonder if there is some direct way of getting the destination.
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Another option would be to use the specifically designed command readlink if available.
E.g.
$ readlink -f `command -v php` /usr/bin/php7.1
Method 2
On Mac OS X and FreeBSD/NetBSD/etc. it’s:
stat -f %Y <filename>
More generically I guess the solution is (stat –printf=%N uses weird quotes):
ls -l b | sed -e 's/.* -> //'
Example:
# ln -s a b # stat -f %Y b a
Another method is:
# find b -maxdepth 0 -printf %l a#
The last line is mangled because it has no newline, but that is fine if you need the result in a variable, like so
# f=$(find b -maxdepth 0 -printf %l) # echo $f a
The -maxdepth is needed to prevent find from descending into directories if b happens to be a directory.
Method 3
This can be done using GNU find: find src -prune -printf "%ln".
Method 4
realpath command of coreutils package,
as linked in readlink command’s manual page.
for example:
realpath /bin/python
outputs
/usr/bin/python2.7
on my machine.
Method 5
On a system where I have no readlink or stat commands but I do have Python 2.x, I’m using a short script:
#!/usr/bin/env python
import os, sys
if __name__ == "__main__":
src = sys.argv[1]
target = os.readlink(src)
if not os.path.isabs(target):
target = os.path.abspath(os.path.join(os.path.dirname(src), target))
print target
Note that unlike readlink -f this may only follow one level of symlink.
Method 6
Portable pure Bash realpath
bash_realpath() {
# print the resolved path
# @params
# 1: the path to resolve
# @return
# &1: the resolved link path
local path="${1}"
while [[ -L ${path} && "$(ls -l "${path}")" =~ -> (.*) ]]
do
path="${BASH_REMATCH[1]}"
done
echo "${path}"
}
Method 7
Portably: no luck except using heuristics to parse ls -l output, or use perl -le 'print readlink("some-file")'
some systems have a readlink command, some with a -f option to obtain the absolute path.
There are various implementations of a stat command as a wrapper for the stat/lstat system calls. The GNU one is not useful in that regard, but zsh’s builtin one is more so:
zmodload zsh/stat stat +link the-link
Still with zsh, you can get the absolute path of a file (removes every symlink component) with the :A modifier (applies to variable expansion, history expansion and globbing:
~$ gstat -c %N b `b' -> `a' ~$ var=b ~$ echo $var:A /home/me/a ~$ echo b(:A) /home/me/a ~$ echo ?(@:A) /home/me/a
Method 8
Added a pure sh version, hoping it to be more portable if bash is not installed :
$ cat ./realpath.sh
#!/usr/bin/env sh
bash_realpath() {
# print the resolved path
# @params
# 1: the path to resolve
# @return
# &1: the resolved link path
for path;do
while [ -L "${path}" ]
do
path="$(ls -l "${path}" | awk '{print $NF}')"
done
which "${path}"
done
}
bash_realpath "[email protected]"
Use case :
$ ./realpath.sh $(which gcc python)
/usr/bin/x86_64-linux-gnu-gcc-6
/usr/bin/python2.7
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0