Linux get link destination

When I’m using ls -la symlinkName or stat symlinkName not all the path is displayed (e.g ../../../one/two/file.txt ) What is the linux command that reveals the full path?

One should be careful here: when ls or stat display no absolute path — the link has no absolute path! This is esp. important when the device is mounted e.g. in a different context (e.g. if you have something on a cd or usb-stick or try to recover some broken hdd). All the mentioned solutions (realpath, readlink. ) show only the absolute path in the mounted context.

10 Answers 10

realpath isn’t available on all linux flavors, but readlink should be.

The above should do the trick.

Alternatively, if you don’t have either of the above installed, you can do the following if you have python 2.6 (or later) installed

python -c 'import os.path; print(os.path.realpath("symlinkName"))' 

realpath should do the trick.

man realpath shows at the bottom that it it part of «GNU coreutils», which I’m pretty sure always comes on Ubuntu, so even though @IanStapletonCordasco says » realpath isn’t available on all linux flavors», it should at least be available on all Ubuntu and Ubuntu derivative flavors I believe.

unix flavors -> ll symLinkName

OSX -> readlink symLinkName

Difference is 1st way would display the sym link path in a blinking way and 2nd way would just echo it out on the console.

The question was asking specifically for the full/absolute path, not relative path (../../file.txt). Both of these answers will give the relative path.

I will give short review and analysis here, but for those TL;DR here is one-liner for bash, useful to anchor the working directory:

script_home=$( dirname $(realpath "$0") ) 

Or you can use any other filename instead of $0 to determine it’s real location.

There is not only problem of detemination of real path of some file, but especially some script is called via symlink from another location and needs to reference other resources relative to it’s real work directory.

Details follow. Lets assume we have real script or file and symbolic link to it:

$ ls -la -rwxr-xr-x 1 root root 0 Mar 20 07:05 realscript.sh lrwxrwxrwx 1 root root 10 Mar 20 07:05 symlink -> realscript.sh 

And the part of GNU coreutils are few very useful commands:

$ realpath symlink /home/test/realscript.sh 
realpath realscript.sh /home/test/realscript.sh 

Also very good combination in scripting is to use dirname on script

$ dirname /home/test/realscript.sh /home/test 

so to wrap it up, you can use in script

echo $( dirname $(realpath "symlink") ) 

or to get and store in variable real script home dir and save code to get real path script realscript.sh:

script_home=$( dirname $(realpath "$0") ) echo Original script home: $script_home 

Where «$0» is defined as «self» in shell script.

To test everything, we put symlink into /home/test2/, amend some additional things and run/call it from root directory:

$ /home/test2/symlink /home/test Original script home: /home/test Original script is: /home/test/realscript.sh Called script is: /home/test2/symlink 

Please try to write your self the amended outputs 🙂

Читайте также:  Создать диск в файле linux

Update 2021, there is also command:

readlink — print resolved symbolic links or canonical file names

DESCRIPTION Note realpath(1) is the preferred command to use for canonicalization functionality.

Источник

Is it possible, executing a file symlinked in /usr/local/bin folder, to get the absolute path of original script? Well, .. I know where original file is, and I know it because I am linkging it. But, . I want this script working, even if I move original source code (and symlink).

coreutils isn’t installed by default on every system that includes bash. stat is more consistently available, but it too has different usage depending on your operating system.

3 Answers 3

readlink is not a standard command, but it’s common on Linux and BSD, including OS X, and it’s the most straightforward answer to your question. BSD and GNU readlink implementations are different, so read the documentation for the one you have.

If readlink is not available, or you need to write a cross-platform script that isn’t bound to a specific implementation:

If the symlink is also a directory, then

will get you into the dereferenced directory, so

echo "I am in $(cd -P "$symlinkdir" && pwd)" 

will echo the fully dereferenced directory. That said, cd -P dereferences the entire path, so if you have more than one symlink in the same path you can have unexpected results.

If the symlink is to a file, not a directory, you may not need to dereference the link. Most commands follow symlinks harmlessly. If you simply want to check if a file is a link, use test -L .

Источник

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.

ln -s /root/Public/mytextfile.txt /root/Public/myothertextfile.txt 

9 Answers 9

Use the -f flag to print the canonicalized version. For example:

readlink -f /root/Public/myothertextfile.txt 
-f, --canonicalize canonicalize by following every symlink in every component of the given name recursively; all but the last component must exist 

To get this working on Mac OS X, brew install coreutils . This installs basic gnu versions of commands prefixed with the letter g , i.e. greadlink -f somefile

Using -f gave me the information that I wanted, i.e. resolving multiple symlinks and showing the end target.

on Ubuntu 18.04.1 LTS (Bionic Beaver) the manpages of readlink have a note saying «Note realpath(1) is the preferred command to use for canonicalization functionality.»

readlink is the command you want. You should look at the man page for the command. Because if you want to follow a chain of symbolic links to the actual file, then you need the -e or -f switch:

$ ln -s foooooo zipzip # fooooo doesn't actually exist $ ln -s zipzip zapzap $ # Follows it, but doesn't let you know the file doesn't actually exist $ readlink -f zapzap /home/kbrandt/scrap/foooooo $ # Follows it, but file not there $ readlink -e zapzap $ # Follows it, but just to the next symlink $ readlink zapzap zipzip 
ls -l /root/Public/myothertextfile.txt 

but readlink would be preferred for use in a script rather than parsing ls .

Читайте также:  Linux mint удаление драйвера nvidia

If you want to show the source and the destination of the link, try stat -c%N files* . E.g.

$ stat -c%N /dev/fd/* ‘/dev/fd/0’ -> ‘/dev/pts/4’ ‘/dev/fd/1’ -> ‘/dev/pts/4’ 

It’s not good for parsing (use readlink for that), but it shows link name and destination, without the clutter of ls -l

-c can be written —format and %N means “quoted file name with dereference if symbolic link”.

The readlink is a good thing, but GNU-specific and non cross platform. I used to write cross platform scripts for /bin/sh , therefore I’d use something like:

 ls -l /root/Public/myothertextfile.txt | awk '' 
 ls -l /root/Public/myothertextfile.txt | awk -F"-> " '' 

but these needs to be tested on different platforms. I think they’ll work, but don’t 100% sure for ls output format.

The result of ls can also be parsed within bash without depending on an external command like awk , sed or perl .

This bash_realpath function, resolves the final destination of a link (link→link→link→final):

bash_realpath() < # print the resolved path # @params # 1: the path to resolve # @return # >&1: the resolved link path local path="$" while [[ -L $ && "$(ls -l "$")" =~ -\>\ (.*) ]] do path="$" done echo "$" > 

If you can’t use readlink , then parsing the result of ls -l could be done like this.

The normal result would be:

ls -l /root/Public/myothertextfile.txt lrwxrwxrwx 1 root root 30 Jan 1 12:00 /root/Public/myothertextfile.txt -> /root/Public/mytextfile.txt 

So we want to replace everything before » -> » and the arrow included. We could use sed for this:

ls -l /root/Public/myothertextfile.txt | sed 's/^.* -> //' /root/Public/mytextfile.txt 

The question is not accurate enough to give a simple answer as the one of brian-brazil:

will indeed dereference every symlink involved in the path construct to the final target behind some_path .

But one level of cascading symlinks is just a particular case among others in a system, the general case being N levels of cascading symlinks. Look at the following on my system:

$ rwhich emacs /usr/bin/emacs /etc/alternatives/emacs /usr/bin/emacs24-x 

rwhich is my own recursive implementation of which that prints all of the intermediate cascading symlinks (to stderr) down to the final target (to stdout).

Then if I want to know what is:

    the target of symlink /usr/bin/emacs**, the obvious answer to me is /etc/alternatives/emacs as returned by:

readlink $(which emacs) readlink /usr/bin/emacs 
readlink -f $(which emacs) readlink -f /usr/bin/emacs rwhich emacs 2>/dev/null 

Источник

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.

Actually wanting src -> dst as the output, hence finding this question, I found that stat -N src didn’t work, but that stat -c»%N» src came close (RHEL7).

Читайте также:  Process administration in linux

8 Answers 8

Another option would be to use the specifically designed command readlink if available.

$ readlink -f `command -v php` /usr/bin/php7.1 

@tommy.carstensen readlink(1) was added to GNU coreutils in 2003, so these days you can likely depend on it on practically all systems using coreutils. (Cf. git.savannah.gnu.org/cgit/coreutils.git/commit/src/…)

readlink can give trouble in scripts, it return the destination of the link, relative to the link. readlink -f only gives the final destination. If you where looking to copy the symlink and its destination in the script, the symlink will break if it was pointing to another symlink. The intermediate will be missing.

On Mac OS X and FreeBSD/NetBSD/etc. it’s:

More generically I guess the solution is (stat —printf=%N uses weird quotes):

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

I totally skimmed over, stat —printf=’%N\n’ is exactly what I want, weird quotes don’t bother me, their the same quotes rm and ln —interactive use

This apparently isn’t portable because on Linux, the GNU coreutils’ stat(1) has different parameters and prints out link -> dest in the output. The find(1) solution should be checked if it’s with GNU findutils or otherwise.

Please don’t forget to quote your variable expansions, echo $f certainly does not produce what you expect when the symlink points to /* (yes it’s possible)

This can be done using GNU find : find src -prune -printf «%l\n» .

realpath command of coreutils package,

as linked in readlink command’s manual page.

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.

Portable pure Bash realpath

bash_realpath() < # print the resolved path # @params # 1: the path to resolve # @return # &1: the resolved link path local path="$" while [[ -L $ && "$(ls -l "$")" =~ -\>\ (.*) ]] do path="$" done echo "$" > 

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 

Источник

Оцените статью
Adblock
detector