Skip to content

Introduction to Python for Sysadmins

Version: 0.2 Year: 2026


Copyright (c) 2025-2026 Ryan Thomas Robson / Robworks Software LLC. Licensed under CC BY-NC-ND 4.0. You may share this material for non-commercial purposes with attribution, but you may not distribute modified versions.


Python has become the de facto standard for systems automation and tool building. Its clean syntax and extensive standard library make it an ideal choice for replacing complex shell scripts and integrating with modern APIs. If you can write a Bash one-liner, you can learn Python - and the payoff is scripts that are easier to read, test, and maintain.

graph TD
    A[Python Source Code .py] --> B[Interpreter]
    B --> C[Standard Library]
    B --> D[External Packages pip]
    B --> E[System Operations]
    E --> F[Files]
    E --> G[Network]
    E --> H[Subprocesses]

Python 2 vs Python 3

Python 2 reached end of life on January 1, 2020. No security patches, no bug fixes, nothing. Every new project should use Python 3, and most distributions now ship Python 3 as the default python3 binary.

The practical differences you'll encounter:

Feature Python 2 Python 3
Print print "hello" (statement) print("hello") (function)
Division 5 / 2 returns 2 5 / 2 returns 2.5
Strings ASCII by default Unicode by default
Input raw_input() input()

If you encounter a legacy script that starts with #!/usr/bin/python (without the 3), check which version it targets before running it.

Always use python3 explicitly

On many systems, python may point to Python 2 or may not exist at all. Always use python3 and pip3 (or python3 -m pip) in your scripts and documentation. This avoids ambiguity on systems where both versions are installed.


Environment Setup

One of the most important concepts in Python development is the virtual environment. It creates an isolated space for each project's dependencies, so installing a library for one script doesn't break another.

Why Virtual Environments Matter

Without a virtual environment, pip install puts packages in the system Python's site-packages directory. This causes problems:

  • Two projects need different versions of the same library.
  • A pip install --upgrade breaks a working script because another script depended on the old version.
  • System tools written in Python (like apt on Ubuntu) can break if you modify the system Python's packages.

Using venv

venv is the standard tool for creating virtual environments. It ships with Python 3 - no installation needed.

# Create a virtual environment in a directory named 'venv'
python3 -m venv venv

# Activate the environment (your prompt changes to show it's active)
source venv/bin/activate

# Now pip installs go into this environment only
pip install requests

# See what's installed in this environment
pip list

# Save dependencies to a file (for reproducibility)
pip freeze > requirements.txt

# Deactivate when finished
deactivate

System Python vs user Python

On Ubuntu 23.04+, pip install outside a virtual environment is blocked by default (PEP 668). You'll see an "externally-managed-environment" error. This is by design - it prevents you from accidentally breaking system tools. Always use a virtual environment for project dependencies.


Basic Syntax

Python uses indentation to define blocks of code, rather than braces or keywords. This enforces readability but can trip you up if you mix tabs and spaces (don't - use spaces, and configure your editor for 4-space indentation).

# A simple script to check disk usage
import shutil

def check_disk(path):
    total, used, free = shutil.disk_usage(path)
    percent_used = (used / total) * 100

    if percent_used > 90:
        print(f"WARNING: Disk usage at {percent_used:.2f}% on {path}")
    else:
        print(f"Disk usage is healthy: {percent_used:.2f}%")

check_disk("/")

Key Differences from Shell Scripting

Shell Python Notes
name="Junie" name = "Junie" No $ prefix, spaces around =
echo "$name" print(name) or print(f"{name}") f-strings for formatting
Arrays are awkward Lists, dicts, sets built in First-class data structures
source util.sh import util Module system with namespaces
$1, $2 sys.argv[1], sys.argv[2] Or use argparse for flags
[[ -f file ]] os.path.isfile("file") Or pathlib.Path("file").is_file()

The REPL

Python ships with an interactive interpreter - the REPL (Read-Eval-Print Loop). It's invaluable for testing snippets, exploring modules, and debugging.

$ python3
>>> import os
>>> os.cpu_count()
8
>>> os.getenv("HOME")
'/home/admin'
>>> help(os.path.isfile)
>>> exit()

Variables and Types

Python is dynamically typed - you don't declare variable types. The interpreter infers them from the assigned value.

hostname = "web01"           # str
port = 8080                  # int
load_average = 2.45          # float
is_active = True             # bool
tags = ["prod", "us-east"]   # list
config = {"debug": False}    # dict

Type Checking at Runtime

# Check a variable's type
type(hostname)    # <class 'str'>
type(port)        # <class 'int'>

# Convert between types
str(port)         # "8080"
int("8080")       # 8080
float("2.45")     # 2.45

Common Built-in Functions

These are functions you'll use constantly:

Function Purpose Example
len() Length of a collection or string len("hello") returns 5
range() Generate a sequence of numbers range(5) produces 0, 1, 2, 3, 4
type() Check a value's type type(42) returns <class 'int'>
str(), int(), float() Type conversion int("42") returns 42
sorted() Return a sorted copy sorted([3, 1, 2]) returns [1, 2, 3]
enumerate() Loop with index for i, v in enumerate(items)
zip() Loop over multiple lists for a, b in zip(names, ips)
input() Read user input name = input("Enter name: ")

Error Handling

Things go wrong: files are missing, networks are down, users provide bad input. Python uses try/except blocks to handle errors gracefully instead of crashing.

import json

def load_config(path):
    try:
        with open(path) as f:
            return json.load(f)
    except FileNotFoundError:
        print(f"Config file not found: {path}")
        return {}
    except json.JSONDecodeError as e:
        print(f"Invalid JSON in {path}: {e}")
        return {}

config = load_config("settings.json")

The pattern is: try the operation, except specific errors you expect, and handle them meaningfully. Avoid bare except: (catches everything including keyboard interrupts) - always catch specific exception types.


Making Scripts Executable

To run a Python script like a regular command (without typing python3 every time):

#!/usr/bin/env python3
"""Check disk usage and warn if above threshold."""

import shutil
import sys

def main():
    path = sys.argv[1] if len(sys.argv) > 1 else "/"
    total, used, free = shutil.disk_usage(path)
    percent = (used / total) * 100

    if percent > 90:
        print(f"CRITICAL: {path} at {percent:.1f}%")
        sys.exit(2)
    elif percent > 75:
        print(f"WARNING: {path} at {percent:.1f}%")
        sys.exit(1)
    else:
        print(f"OK: {path} at {percent:.1f}%")
        sys.exit(0)

if __name__ == "__main__":
    main()
# Make it executable
chmod +x check_disk.py

# Run it directly
./check_disk.py /home

The #!/usr/bin/env python3 shebang line tells the OS to use whichever python3 is on the PATH. The if __name__ == "__main__" guard ensures main() only runs when the script is executed directly, not when it's imported as a module by another script.


Interactive Quizzes



Further Reading


Next: Data Structures and Logic | Back to Index

Comments