143

Say that I setup a symbolic link:

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

is there a way to see what the target of myothertextfile.txt is using the command line?

Jared
  • 1,577
  • 2
  • 12
  • 12

9 Answers9

187

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

readlink -f /root/Public/myothertextfile.txt

From man readlink:

-f, --canonicalize
      canonicalize by following every symlink in every component of the given name recursively; all but the last component must exist
d4nyll
  • 334
  • 2
  • 9
brian-brazil
  • 3,904
  • 1
  • 20
  • 15
  • 8
    As suggested in [another question](https://superuser.com/questions/330199/how-get-full-path-to-target-of-link), you may want to use `readlink -f`. – Denilson Sá Maia Jun 07 '14 at 00:14
  • 5
    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` – Mike D Feb 21 '16 at 20:47
  • with -f switch, command returns nothing in my case.. – sotn Jul 19 '18 at 08:08
  • Using -f gave me the information that I wanted, i.e. resolving multiple symlinks and showing the end target. – isapir Oct 15 '18 at 19:52
  • 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." – Shmuel Kamensky Jul 01 '19 at 15:32
24

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
Kyle Brandt
  • 82,107
  • 71
  • 302
  • 444
6

This will also work:

ls -l /root/Public/myothertextfile.txt

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

Dennis Williamson
  • 60,515
  • 14
  • 113
  • 148
5

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

bishop
  • 1,077
  • 10
  • 16
Robert Siemer
  • 543
  • 9
  • 19
3

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 '{print $NF}'

or:

 ls -l /root/Public/myothertextfile.txt | awk -F"-> " '{print $2}'

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="${1}"
  while [[ -L ${path} && "$(ls -l "${path}")" =~ -\>\ (.*) ]]
  do
    path="${BASH_REMATCH[1]}"
  done
  echo "${path}"
}
Léa Gris
  • 113
  • 4
1

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
7ochem
  • 280
  • 1
  • 3
  • 12
1

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

readlink -f some_path

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
    
  • the final target behind cascading symlinks /usr/bin/emacs, the answer shall be /usr/bin/emacs24-x as returned by:

    readlink -f $(which emacs)
    readlink -f /usr/bin/emacs
    rwhich emacs 2>/dev/null
    
Nico
  • 11
  • 1
0

ll or ls -l should list the directory items, including your symbolic link and it's target

cd -P /root/Public/myothertextfile.txt (in your case) should point to the original path

Mantz
  • 1
0

If you find the target of all links within a folder and its subfolder use the find . -type l -ls command with link type as follows:

me@local.localdomain:~/test$ find . -type l -ls
8601855888        0 lrwxr-xr-x    1 me           staff                   6 Jan 24 19:53 ./link -> target

If you want the target of a single, then ls -l should work:

me@local.localdomain:~/test$ ls -l 
total 0
lrwxr-xr-x  1 me  staff  6 Jan 24 19:53 link -> target
-rw-r--r--  1 me  staff  0 Jan 24 19:53 target
Mat
  • 1,783
  • 4
  • 22
  • 39
Memin
  • 101
  • 2