How to Trace and Display Full Symbolic Link Chains in Linux


2 views

When working with symbolic links in Linux, you might encounter situations where links form a chain:

mkdir a
ln -s a b
ln -s b c
ln -s c d

The standard ls -l command only shows the immediate reference:

$ ls -l d
lrwxrwxrwx 1 user user 1 Jan 1 12:00 d -> c

Using the readlink Command

The most straightforward solution is to use readlink with the -f flag:

$ readlink -f d
/home/user/a

For step-by-step resolution:

$ readlink d
c
$ readlink c
b
$ readlink b
a

Creating a Custom Shell Function

Add this to your .bashrc for easier use:

trace_link() {
    local link=$1
    while [ -L "$link" ]; do
        ls -ld "$link"
        link=$(readlink "$link")
    done
    echo "Final target: $link"
}

Usage example:

$ trace_link d
lrwxrwxrwx 1 user user 1 Jan 1 12:00 d -> c
lrwxrwxrwx 1 user user 1 Jan 1 12:00 c -> b
lrwxrwxrwx 1 user user 1 Jan 1 12:00 b -> a
Final target: a

Using find with -follow

For discovering all symlinks in a directory:

find /path -type l -follow -exec ls -l {} \;

Python Script for Detailed Analysis

#!/usr/bin/env python3
import os
import sys

def trace_symlink(path):
    print(f"Tracing: {path}")
    while os.path.islink(path):
        target = os.readlink(path)
        print(f"{path} -> {target}")
        path = os.path.join(os.path.dirname(path), target)
    print(f"Final target: {path}")

if __name__ == "__main__":
    trace_symlink(sys.argv[1])

Be aware of:

  • Circular references which can cause infinite loops
  • Broken links in the chain
  • Permission issues when traversing directories

For production environments, consider adding checks for these conditions in any custom scripts.


When working with symbolic links in Unix/Linux systems, you might create chains of symlinks where one link points to another link. For example:

mkdir a
ln -s a b
ln -s b c
ln -s c d

Standard tools like ls -l only show the immediate reference:

$ ls -l d
lrwxrwxrwx 1 user group 1 date d -> c

The readlink command with -f flag resolves the entire chain:

$ readlink -f d
/home/user/a

For a step-by-step resolution without final canonicalization:

$ readlink -e d
/home/user/a

Create a bash function to display the complete chain:

function symlink_chain() {
    local target="$1"
    while [[ -L "$target" ]]; do
        ls -l "$target" | awk '{printf "%s -> ", $9}'
        target=$(readlink "$target")
    done
    echo "$target"
}

Usage example:

$ symlink_chain d
d -> c -> b -> a

The namei utility from util-linux provides detailed path resolution:

$ namei -l d
f: d
l d -> c
f: c
l c -> b
f: b
l b -> a
drwxr-xr-x root root a

For more complex scenarios, here's a Python script:

#!/usr/bin/env python3
import os
import sys

def print_symlink_chain(path):
    print(path, end='')
    while os.path.islink(path):
        path = os.readlink(path)
        print(' ->', path, end='')
    print()

if __name__ == '__main__':
    print_symlink_chain(sys.argv[1])