Symbolic link (symlink)
ln -s /path/to/original /path/to/link
ln -s /etc/nginx/nginx.conf ~/nginx.conf
Hard link
ln /path/to/original /path/to/link
ln /var/log/app.log ~/app.log
Differences
Symbolic link:
- Points to path (string)
- Can link directories
- Can cross filesystems
- Breaks if original is moved/deleted
- Shows as link in
ls -l
Hard link:
- Points to inode
- Cannot link directories
- Must be same filesystem
- Survives original deletion
- Indistinguishable from original
Create symlink to directory
ln -s /var/www/html ~/www
ln -s ~/Documents/project ~/proj
Force overwrite
ln -sf /new/target existing-link
Relative symlink
# Absolute
ln -s /absolute/path/file link
# Relative
cd /path/to
ln -s ../another/file link
List symlinks
ls -l | grep '^l'
find . -type l
Check what symlink points to
ls -l link
readlink link
readlink -f link # Canonical path
Find broken symlinks
find . -xtype l
find . -type l ! -exec test -e {} \; -print
Remove symlink
rm link
unlink link
# Don't use rm -r on symlink to directory!
Count hard links
ls -l file # Number after permissions
stat file | grep Links
Find all hard links to file
find / -samefile /path/to/file
find / -inum $(stat -c %i file)
Common use cases
Config files
# Link config to home
ln -s /etc/nginx/nginx.conf ~/.config/nginx.conf
# Version control config
ln -s ~/dotfiles/.vimrc ~/.vimrc
Executables
# Make command available
sudo ln -s /opt/app/bin/app /usr/local/bin/app
Web directories
# Apache/Nginx document root
sudo ln -s /home/user/project /var/www/html/project
Shared libraries
sudo ln -s /usr/lib/libfoo.so.1.2.3 /usr/lib/libfoo.so.1
Multiple links
# Create links in target directory
ln -st /target/dir file1 file2 file3
Backup before overwrite
ln -sb /new/target existing-link
# Creates existing-link~ backup
Interactive mode
ln -si source target
# Prompts before overwrite
Verbose output
ln -sv source target
Check if path is symlink
# In script
if [ -L "$path" ]; then
echo "Is a symlink"
fi
Update all symlinks in directory
find . -type l -exec sh -c '
target=$(readlink "$1")
new_target=$(echo "$target" | sed "s|old|new|")
ln -sf "$new_target" "$1"
' _ {} \;
Troubleshooting
Permission denied
# Check original file permissions
ls -l /path/to/original
# Check parent directory permissions
ls -ld /path/to/
Too many levels of symbolic links
# Circular symlink
ls -l link
readlink -f link # Shows error
Cross-device link (trying hard link across filesystems)
# Use symlink instead
ln -s /mnt/otherdisk/file ~/link