The os module in the Python standard library gives you access to operating system features like environment variables, the current working directory, file permissions, and process management. It is one of the oldest and most widely used modules in Python, and many higher-level tools like pathlib build on top of it.
import os
print(os.getcwd()) # /Users/maya/Dev/project
print(os.name) # posix
print(os.environ.get("HOME")) # /Users/mayaos.getcwd() returns the current working directory as a string. os.name tells you the platform: "posix" on Linux and macOS, "nt" on Windows. os.environ is a dictionary-like object containing environment variables.
Working with environment variables
Environment variables store configuration values like API keys, database URLs, and runtime settings outside your code. Reading them through os.environ keeps secrets and per-machine settings out of your source files entirely.
import os
home = os.environ["HOME"]
path = os.environ.get("PATH", "/usr/bin")
user = os.environ.get("USER", "unknown")
print(home) # /Users/maya
print(path[:50]) # /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
print(user) # mayaos.environ["HOME"] raises a KeyError if the variable is not set. os.environ.get("PATH", "/usr/bin") returns the default value "/usr/bin" when the variable is missing. Always use .get() with a sensible default for optional variables.
You can also set environment variables for the current process:
import os
os.environ["APP_MODE"] = "testing"
print(os.environ["APP_MODE"]) # testingThis change is visible to child processes spawned by your Python program but does not affect the parent shell or other programs.
Navigating directories
The os module provides functions for checking and changing the current working directory.
import os
print(os.getcwd()) # /Users/maya/Dev/project
os.chdir("/tmp")
print(os.getcwd()) # /tmp
os.chdir(os.environ["HOME"])
print(os.getcwd()) # /Users/mayaos.chdir(path) changes the current working directory. This affects all subsequent relative path operations in your script. It is often safer to use absolute paths with pathlib instead of changing the working directory mid-script.
Listing directory contents
os.listdir() returns the names of entries in a directory as strings.
import os
entries = os.listdir(".")
for entry in sorted(entries)[:5]:
print(entry)Sorting first makes the output predictable, since the raw list from os.listdir comes back in whatever order the filesystem happens to store entries:
README.md
src
testsos.listdir(".") lists the current directory. The result is unsorted and includes both files and directories as plain names. For Path objects and more control, prefer pathlib.Path.iterdir().
To separate files from directories, combine os.listdir with os.path:
import os
entries = os.listdir(".")
files = [e for e in entries if os.path.isfile(e)]
dirs = [e for e in entries if os.path.isdir(e)]
print(f"{len(files)} files, {len(dirs)} directories")Creating and removing directories
The os module can create single directories or nested trees in one call, which saves you from writing a loop to build out a multi-level folder structure by hand.
import os
os.makedirs("output/2026/reports", exist_ok=True)
os.mkdir("output/temp")
os.rmdir("output/temp")os.makedirs("output/2026/reports", exist_ok=True) creates all three directories if they do not exist. exist_ok=True prevents an error when the path already exists.
os.mkdir creates a single directory and fails if the parent does not exist. os.rmdir removes an empty directory.
Running external commands
os.system() runs a shell command and returns its exit code. However, the official Python documentation recommends using the subprocess module instead.
import os
exit_code = os.system("echo 'Hello from the shell'")
print(f"Exit code: {exit_code}")The command runs through the shell, prints its own output directly to the terminal, and then Python prints the numeric exit code it returned:
Hello from the shell
Exit code: 0os.system() is simple but has serious limitations: it always passes the command through the shell (a security risk with user input), it does not capture output programmatically, and it gives you no control over timeouts or error handling.
Use subprocess.run() for all new code:
import subprocess
result = subprocess.run(
["echo", "Hello from subprocess"],
capture_output=True,
text=True,
)
print(result.stdout.strip())Because capture_output=True redirects the child process's output back into Python instead of the terminal, the result only appears once you explicitly print it:
Hello from subprocesssubprocess.run() takes a list of arguments (no shell injection risk), captures stdout and stderr, and supports timeouts, working directories, and environment variable overrides.
Useful os.path functions
The os.path submodule provides path manipulation functions. For new code, prefer pathlib, but you will encounter os.path in existing codebases.
import os
path = "/Users/maya/Documents/report.pdf"
print(os.path.basename(path)) # report.pdf
print(os.path.dirname(path)) # /Users/maya/Documents
print(os.path.splitext(path)) # ('/Users/maya/Documents/report', '.pdf')
print(os.path.exists(path)) # False
print(os.path.join("data", "2026", "output.csv")) # data/2026/output.csv| os.path function | pathlib equivalent |
|---|---|
| os.path.basename(p) | Path(p).name |
| os.path.dirname(p) | Path(p).parent |
| os.path.splitext(p) | Path(p).suffix |
| os.path.exists(p) | Path(p).exists() |
| os.path.join(a, b) | Path(a) / b |
The pathlib versions are more readable and return Path objects instead of strings.
Practical example: inspecting the runtime environment
Combine several os features to write a script that reports information about the Python process.
import os
print("Platform:", os.name)
print("Current directory:", os.getcwd())
print("Home:", os.environ.get("HOME", "not set"))
print("Python path:", os.environ.get("PYTHONPATH", "not set"))
pid = os.getpid()
print(f"Process ID: {pid}")
files = [f for f in os.listdir(".") if os.path.isfile(f)]
print(f"Files in current directory: {len(files)}")os.getpid() returns the process ID of the current Python interpreter. This is useful for logging, creating unique temporary file names, or debugging multi-process applications.
Common mistakes
Using os.system() for command execution. It is tempting because it is short, but os.system() is a security risk and gives you no output capture. Use subprocess.run() with a list of arguments instead.
Forgetting that os.listdir returns only names. os.listdir("data") returns ["file.txt"], not ["data/file.txt"]. You need to join with the directory path to get a usable path: os.path.join("data", name).
Changing directory with os.chdir unnecessarily. Changing the working directory affects all relative paths in your program and can cause hard-to-debug issues in larger scripts or threaded code. Use absolute paths or pathlib paths instead.
Hardcoding path separators. Never write "data\2026" or "data/2026" with hardcoded separators. Use os.path.join("data", "2026") or Path("data") / "2026" for cross-platform compatibility.
Rune AI
Key Insights
- Use
os.environto read and set environment variables. - Use
os.getcwd()andos.chdir()to work with the current working directory. - Use
os.listdir()for a quick directory listing; preferpathlib.Path.iterdir()for new code. - Use
os.makedirs()withexist_ok=Trueto create nested directories safely. - Use
subprocess.run()instead ofos.system()for running external commands. - Changes to
os.environonly affect the current Python process and its children.
Frequently Asked Questions
Should I use os.system() or subprocess.run() to run shell commands?
What is the difference between os.getcwd() and Path.cwd()?
Can I change environment variables for other programs from Python?
Conclusion
The os module is Python's primary interface to the operating system. Use os.environ for environment variables, os.getcwd and os.chdir for directory navigation, and os.listdir for basic directory listing. For running external commands, prefer subprocess.run over os.system. For file path operations, prefer pathlib over raw os.path functions.
More in this topic
What Is the Python Standard Library?
Learn what the Python standard library is, why it matters, and how to use its built-in modules without installing anything extra.
Python `math` Module Explained
Learn how to use the Python math module for square roots, rounding, trigonometry, logarithms, and mathematical constants.
Format Dates and Times in Python
Learn how to use strftime and strptime to format dates as strings and parse date strings into Python datetime objects.