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])