Complete guide to Python's os.symlink function covering symbolic link creation, management, and practical examples.
Last modified April 11, 2025
This comprehensive guide explores Python’s os.symlink function, which creates symbolic links (symlinks) between files. We’ll cover link types, cross-platform behavior, and practical file system linking examples.
The os.symlink function creates a symbolic link pointing to a target file or directory. Symlinks are references that act like the target.
Key parameters: src (target path), dst (link path), target_is_directory (Windows-specific flag). Requires appropriate permissions on both paths.
The simplest use of os.symlink creates a symbolic link to a file. This example shows basic link creation and verification.
basic_symlink.py
import os
target = “original.txt” with open(target, “w”) as f: f.write(“This is the original file”)
link = “link_to_original.txt” os.symlink(target, link)
if os.path.islink(link): print(f"{link} is a symlink pointing to {os.readlink(link)}") with open(link) as f: print(f"Content: {f.read()}") else: print(“Symlink creation failed”)
This creates a target file, then a symlink pointing to it. The code verifies the link and reads through it. Symlinks behave like the target file.
Note that symlinks can become broken if the target is moved or deleted.
Symlinks can also point to directories. This example demonstrates directory symlink creation and traversal.
dir_symlink.py
import os
target_dir = “original_dir” os.makedirs(target_dir, exist_ok=True)
with open(os.path.join(target_dir, “file.txt”), “w”) as f: f.write(“File in original directory”)
link_dir = “link_to_dir” os.symlink(target_dir, link_dir, target_is_directory=True)
if os.path.islink(link_dir): print(f"{link_dir} links to {os.readlink(link_dir)}") print(“Contents:”, os.listdir(link_dir)) with open(os.path.join(link_dir, “file.txt”)) as f: print(f.read()) else: print(“Directory symlink creation failed”)
This creates a directory, adds a file to it, then makes a symlink to the directory. The code verifies the link and accesses files through it.
On Windows, target_is_directory=True is required for directory symlinks.
Symlinks can use either relative or absolute paths. This affects behavior when files are moved. This example shows both approaches.
relative_absolute.py
import os
os.makedirs(“data/files”, exist_ok=True) with open(“data/files/target.txt”, “w”) as f: f.write(“Target file content”)
os.symlink(“files/target.txt”, “data/relative_link.txt”)
abs_path = os.path.abspath(“data/files/target.txt”) os.symlink(abs_path, “data/absolute_link.txt”)
print(“Relative link points to:”, os.readlink(“data/relative_link.txt”)) print(“Absolute link points to:”, os.readlink(“data/absolute_link.txt”))
os.chdir(“data”) print("\nAfter changing directory:") print(“Relative still works:”, open(“relative_link.txt”).read()) print(“Absolute still works:”, open(“absolute_link.txt”).read())
Relative links maintain their relationship when the containing directory moves. Absolute links break if the target moves but work from any location.
Choose relative links for portable directory structures, absolute for fixed locations.
Attempting to create a symlink where one exists raises FileExistsError. This example shows proper handling of existing symlinks.
existing_symlinks.py
import os import errno
target = “target_file.txt” link = “existing_link.txt”
with open(target, “w”) as f: f.write(“Original content”) os.symlink(target, link)
def create_symlink(src, dst): try: os.symlink(src, dst) except FileExistsError: if os.path.islink(dst): print(f"Symlink {dst} already exists") # Optionally update existing symlink os.remove(dst) os.symlink(src, dst) print(f"Updated {dst} to point to {src}") else: print(f"{dst} exists but isn’t a symlink")
create_symlink(target, link) create_symlink(target, “regular_file.txt”) # This would fail
The create_symlink function safely handles existing symlinks. It checks if the existing path is a symlink before attempting to overwrite it.
For non-symlink files, you might want different handling to avoid data loss.
Windows handles symlinks differently than Unix. This example shows Windows- specific considerations, including privilege requirements.
windows_symlinks.py
import os import sys import ctypes
def is_admin(): try: return ctypes.windll.shell32.IsUserAnAdmin() except: return False
if sys.platform == “win32”: target = “C:\Windows\notepad.exe” link = “notepad_link.exe”
if is_admin():
try:
# On Windows, need admin privileges or developer mode
os.symlink(target, link, target_is_directory=False)
print(f"Created symlink from {link} to {target}")
# Verify
if os.path.islink(link):
print("Link verified")
os.startfile(link) # Try opening through symlink
except OSError as e:
print(f"Symlink creation failed: {e}")
else:
print("This script requires admin privileges on Windows")
else: print(“This example is for Windows only”)
Windows requires either admin privileges or developer mode enabled for symlink creation. The code checks for admin rights before attempting to create links.
The target_is_directory parameter is crucial on Windows for proper symlink type creation.
Python provides functions to check for and read symlinks. This example demonstrates symlink detection and inspection.
inspect_symlinks.py
import os
os.makedirs(“test_dir”, exist_ok=True) with open(“test_dir/original.txt”, “w”) as f: f.write(“Original content”) os.symlink(“original.txt”, “test_dir/link.txt”)
def inspect_path(path): print(f"\nInspecting {path}:") print(f"exists(): {os.path.exists(path)}") print(f"lexists(): {os.path.lexists(path)}") print(f"islink(): {os.path.islink(path)}")
if os.path.islink(path):
print(f"readlink(): {os.readlink(path)}")
print(f"Actual content: {open(path).read()}")
inspect_path(“test_dir/original.txt”) inspect_path(“test_dir/link.txt”) inspect_path(“test_dir/nonexistent.txt”) inspect_path(“test_dir/broken_link.txt”) # Create broken link os.symlink(“nonexistent.txt”, “test_dir/broken_link.txt”) inspect_path(“test_dir/broken_link.txt”)
The inspect_path function shows various symlink inspection methods. os.path.exists follows symlinks, while os.path.lexists checks the link itself.
Broken links return True for lexists() and islink() but False for exists().
This example demonstrates writing code that handles symlinks across different operating systems, accounting for platform differences.
cross_platform.py
import os import sys import platform
def create_symlink_crossplatform(src, dst): “““Create symlink handling platform differences””” try: if sys.platform == “win32”: # Windows requires directory flag is_dir = os.path.isdir(src) os.symlink(src, dst, target_is_directory=is_dir) else: os.symlink(src, dst) print(f"Created symlink from {dst} to {src}") except OSError as e: print(f"Failed to create symlink: {e}") if sys.platform == “win32” and e.winerror == 1314: print(“On Windows, you need admin privileges or developer mode”)
target_file = “data.txt” target_dir = “docs” link_file = “data_link.txt” link_dir = “docs_link”
with open(target_file, “w”) as f: f.write(“Test data”) os.makedirs(target_dir, exist_ok=True)
create_symlink_crossplatform(target_file, link_file) create_symlink_crossplatform(target_dir, link_dir)
print("\nVerification:") for link in [link_file, link_dir]: if os.path.lexists(link): print(f"{link} -> {os.readlink(link)}") else: print(f"{link} not created")
This function handles Windows’ target_is_directory requirement automatically. It also provides helpful error messages for Windows privilege issues.
The verification step uses lexists() to check for both valid and broken links.
Symlink attacks: Be cautious with untrusted symlink paths
Privilege escalation: Symlinks can expose sensitive files
Windows privileges: Admin rights often required
Broken links: Always check link validity before use
Relative paths: More portable but can break if moved
Check platform: Handle Windows and Unix differences
Verify links: Use islink() before operations
Handle errors: Catch OSError for permission issues
Prefer relative: For portable directory structures
Document targets: Make symlink purposes clear
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.