Skip to content

Python und das Betriebssystem

Mit Dateien, Prozessen, Umgebungsvariablen und Systeminformationen arbeiten und Python in die tägliche Administration integrieren.

Einer der häufigsten Einsatzzwecke von Python im Administrationsalltag ist die Interaktion mit dem Betriebssystem. Dateien müssen verarbeitet, Verzeichnisse durchsucht, externe Programme gestartet und Systeminformationen ausgewertet werden.

Viele Aufgaben, die früher ausschließlich mit Shell-Skripten gelöst wurden, lassen sich mit Python strukturierter, robuster und leichter wartbar umsetzen. Gleichzeitig kann Python bestehende Werkzeuge und Betriebssystemfunktionen weiterhin nutzen.

In diesem Kapitel lernen Sie, wie Python mit dem Betriebssystem zusammenarbeitet und wie typische Administrationsaufgaben automatisiert werden können.

Dateien und Verzeichnisse verwalten

Dateien erstellen und schreiben

Die Basis jeder Dateiverwaltung ist das Erstellen und Schreiben von Dateien. In Python geschieht dies mit der eingebauten Funktion open(). Im Gegensatz zu Java oder C# ist das Öffnen einer Datei in Python sehr einfach und flexibel.

# Eine neue Logdatei erstellen und eine Zeile schreiben
with open('server.log', 'w', encoding='utf-8') as log_file:
    log_file.write('Server gestartet am 2024-06-01 08:00\n')

Der with-Block sorgt dafür, dass die Datei automatisch geschlossen wird, auch wenn ein Fehler auftritt. Das ist eine bewährte Praxis, die Ressourcensicherheit garantiert.

Dateien lesen

Zum Auslesen von Dateien bietet sich ebenfalls open() an:

with open('server.log', 'r', encoding='utf-8') as log_file:
    for line in log_file:
        print(line.strip())  # Zeilen einzeln verarbeiten

Das zeilenweise Lesen ist besonders bei großen Logdateien effizient, da nicht die gesamte Datei auf einmal geladen wird.

Dateien löschen und umbenennen

Für Dateioperationen wie Löschen oder Umbenennen verwendet man das os-Modul:

import os

# Datei löschen
if os.path.exists('old_backup.zip'):
    os.remove('old_backup.zip')

# Datei umbenennen
os.rename('temp.log', 'server.log')

Vor dem Löschen empfiehlt sich immer eine Existenzprüfung, um Fehler zu vermeiden.

Dateien kopieren

Das shutil-Modul bietet Funktionen für das Kopieren von Dateien und Verzeichnissen, was in der Shell oft mit cp oder copy erledigt wird:

import shutil

# Datei kopieren
shutil.copy('server.log', 'backup/server.log.bak')

Dies ist nützlich für Backup-Skripte oder das Verschieben von Konfigurationsdateien.

Verzeichnisse erstellen und durchsuchen

Ein häufiger Anwendungsfall ist das Anlegen von Verzeichnissen und das Durchlaufen von Verzeichnisbäumen.

import os

# Verzeichnis erstellen, falls es nicht existiert
os.makedirs('backup/2024-06-01', exist_ok=True)

# Alle Dateien in einem Verzeichnis auflisten
for entry in os.listdir('backup'):
    path = os.path.join('backup', entry)
    if os.path.isfile(path):
        print(f'Datei: {entry}')
    elif os.path.isdir(path):
        print(f'Verzeichnis: {entry}')

Für rekursive Durchsuchungen ist os.walk() ideal:

for root, dirs, files in os.walk('backup'):
    print(f'Im Verzeichnis: {root}')
    for file in files:
        print(f'  Datei: {file}')

Praxisbeispiel: Logdateien archivieren

Ein typisches Admin-Skript archiviert alte Logdateien und verschiebt sie in ein Backup-Verzeichnis:

import os
import shutil
from datetime import datetime, timedelta

log_dir = '/var/log/myapp'
backup_dir = '/var/backups/myapp_logs'

os.makedirs(backup_dir, exist_ok=True)

# Logdateien älter als 7 Tage verschieben
cutoff = datetime.now() - timedelta(days=7)

for filename in os.listdir(log_dir):
    if filename.endswith('.log'):
        filepath = os.path.join(log_dir, filename)
        mtime = datetime.fromtimestamp(os.path.getmtime(filepath))
        if mtime < cutoff:
            dest = os.path.join(backup_dir, filename)
            shutil.move(filepath, dest)
            print(f'Archiviert: {filename}')

Hinweis zu Pfadtrennzeichen

Unter Windows verwendet man \ als Pfadtrenner, unter Linux /. Python's os.path.join() kümmert sich automatisch um das richtige Trennzeichen, was Skripte plattformunabhängig macht.

Zusammenfassung

Python bietet mit open(), os und shutil einfache und mächtige Werkzeuge für die Dateiverwaltung. Im Vergleich zu Shell-Skripten ermöglichen diese Module komplexe Logik, Fehlerbehandlung und Plattformunabhängigkeit in einem einzigen Skript. So lassen sich Routineaufgaben wie Backup, Logrotation oder Konfigurationsmanagement elegant automatisieren.

Mit Umgebungsvariablen arbeiten

Umgebungsvariablen lesen und nutzen

Umgebungsvariablen sind zentrale Konfigurationspunkte im Betriebssystem, die Programme und Skripte steuern können. In Python greift man über das Modul os auf sie zu. Das ist vergleichbar mit dem Zugriff auf Umgebungsvariablen in Bash (VAR) oder PowerShell (Env:VAR).

import os

# Eine Umgebungsvariable lesen
path = os.environ.get('PATH')
print(f'PATH: {path}')

# Standardwert verwenden, falls Variable nicht gesetzt ist
db_host = os.environ.get('DB_HOST', 'localhost')
print(f'Datenbankhost: {db_host}')

Praxis-Tipp: Verwenden Sie os.environ.get(), um Fehler zu vermeiden, wenn eine Variable nicht existiert. Ein direkter Zugriff wie os.environ['VAR'] löst eine Ausnahme aus, wenn die Variable fehlt.

Umgebungsvariablen setzen und ändern

Umgebungsvariablen innerhalb eines laufenden Python-Prozesses zu setzen oder zu ändern, schreibt man in os.environ. Diese Änderungen wirken nur im aktuellen Prozess und dessen Kindprozessen.

import os

# Neue Umgebungsvariable setzen
os.environ['MY_VAR'] = 'wert'

# Variable ändern
os.environ['PATH'] = os.environ.get('PATH', '') + ':/custom/bin'

# Bestätigen
print(os.environ['MY_VAR'])

Wichtig: Änderungen an os.environ beeinflussen nicht die Systemumgebung dauerhaft. Für dauerhafte Änderungen müssen Sie die Variable im Betriebssystem setzen (z.B. in .bashrc, PowerShell-Profil oder Systemsteuerung).

Umgebungsvariablen für Konfigurationen und Zugangsdaten

In der Praxis werden sensible Daten wie API-Schlüssel oder Datenbankpasswörter nicht im Code, sondern in Umgebungsvariablen gespeichert. So bleiben sie getrennt von der Anwendung und können leicht geändert werden.

import os

api_key = os.environ.get('API_KEY')
if not api_key:
    raise RuntimeError('API_KEY ist nicht gesetzt')

# API-Key verwenden
print(f'API-Key Länge: {len(api_key)}')

Best Practice: Dokumentieren Sie, welche Umgebungsvariablen Ihre Skripte erwarten, und prüfen Sie deren Existenz beim Start.

Python Dotenv: Umgebungsvariablen aus Dateien laden

Gerade in Entwicklungs- und Testumgebungen ist es praktisch, Umgebungsvariablen in einer .env-Datei zu speichern, statt sie im System zu setzen. Das Paket python-dotenv liest diese Datei und lädt die Variablen in os.environ.

Installation:

pip install python-dotenv

Beispiel .env-Datei:

DB_HOST=192.168.1.100
DB_USER=admin
DB_PASS=geheim

Python-Skript zum Laden:

from dotenv import load_dotenv
import os

load_dotenv()  # Lädt Variablen aus .env ins os.environ

print(os.environ.get('DB_HOST'))  # Ausgabe: 192.168.1.100

Vorteil gegenüber Shell-Skripten: Dotenv ermöglicht es, Umgebungsvariablen plattformunabhängig und projektbezogen zu verwalten, ohne die globale Shell-Umgebung zu verändern.

Typische Anwendungsfälle in der Administration

  • Automatisierte Backups: Zugangsdaten für entfernte Server oder Cloud-Dienste über Umgebungsvariablen sicher bereitstellen.
  • Monitoring-Skripte: API-Token für Monitoring-Tools aus Umgebungsvariablen lesen.
  • Konfigurationsmanagement: Unterschiedliche Umgebungen (Test, Produktion) durch verschiedene .env-Dateien abbilden.

Zusammenfassung

  • Umgebungsvariablen sind essenziell für flexible und sichere Konfigurationen.
  • os.environ.get() ist der sichere Weg zum Lesen.
  • Änderungen in os.environ wirken nur temporär im Prozess.
  • python-dotenv erleichtert das Management von Umgebungsvariablen in Entwicklungsumgebungen.

Durch den gezielten Einsatz von Umgebungsvariablen mit Python automatisieren Sie administrative Aufgaben effizient und behalten dabei die Kontrolle über sensible Daten.

Externe Programme ausführen

Externe Programme mit subprocess ausführen

In der Systemadministration ist es oft notwendig, externe Programme oder Shell-Kommandos aus Python-Skripten heraus auszuführen, z. B. um Systeminformationen zu sammeln, Dienste zu steuern oder bestehende Werkzeuge in Automatisierungsprozesse einzubinden.

Das moderne und empfohlene Modul dafür ist subprocess. Es ersetzt ältere Module wie os.system und bietet mehr Kontrolle über Eingabe, Ausgabe und Fehlerbehandlung.

Einfaches Ausführen eines Kommandos

Möchten Sie z. B. unter Linux den Befehl ls -l /var/log ausführen und die Ausgabe direkt sehen, verwenden Sie:

import subprocess

# Einfaches Kommando ausführen und Ausgabe direkt auf der Konsole anzeigen
subprocess.run(['ls', '-l', '/var/log'], check=True)

Unter Windows wäre ein vergleichbares Beispiel dir C:\Windows:

subprocess.run(['cmd', '/c', 'dir', 'C:\\Windows'], check=True)

Das Argument check=True sorgt dafür, dass bei einem Fehler (nicht 0 Rückgabewert) eine Ausnahme ausgelöst wird, was Fehler früh sichtbar macht.

Ausgabe eines Kommandos in Python weiterverarbeiten

Oft wollen Sie die Ausgabe eines Kommandos nicht nur sehen, sondern weiterverarbeiten, z. B. um Logdateien zu filtern oder Netzwerkstatus auszuwerten.

result = subprocess.run(
    ['ip', 'addr'],
    capture_output=True,  # Ausgabe wird in result.stdout gespeichert
    text=True,           # Ausgabe als String statt Bytes
    check=True
)

print('IP-Konfiguration:')
print(result.stdout)

Unter Windows könnten Sie ipconfig analog ausführen.

Fehlerausgabe und Rückgabewert auswerten

Neben der Standardausgabe (stdout) ist oft auch die Fehlerausgabe (stderr) relevant:

result = subprocess.run(
    ['systemctl', 'status', 'nginx'],
    capture_output=True,
    text=True
)

if result.returncode == 0:
    print('Nginx läuft.')
else:
    print('Fehler beim Abfragen des Dienststatus:')
    print(result.stderr)

Shell-Kommandos mit shell=True

Manchmal brauchen Sie komplexe Shell-Befehle oder Pipes. Dann können Sie shell=True verwenden:

# Beispiel: Ausgabe von 'ps aux | grep ssh' unter Linux
result = subprocess.run(
    'ps aux | grep ssh',
    shell=True,
    capture_output=True,
    text=True
)
print(result.stdout)

Warnung: shell=True kann Sicherheitsrisiken bergen, wenn Benutzereingaben ungeprüft eingebunden werden. Verwenden Sie es nur, wenn nötig und mit Vorsicht.

Vergleich zu Shell-Skripten

  • Vorteil Python: Bessere Fehlerbehandlung, strukturierte Ausgabe, einfache Weiterverarbeitung von Ergebnissen
  • Shell-Skript: Kürzer für einfache Befehle, aber schwerer zu warten und zu erweitern

Python eignet sich besonders, wenn mehrere externe Werkzeuge kombiniert, deren Ausgaben analysiert oder automatisierte Entscheidungen getroffen werden sollen.

Beispiel: Backup-Verzeichnis mit tar archivieren

Ein typisches Admin-Szenario ist das automatisierte Erstellen von Backups:

import datetime
import subprocess

backup_dir = '/var/backups/myapp'
archive_name = f'/var/backups/myapp_backup_{datetime.date.today()}.tar.gz'

try:
    subprocess.run(
        ['tar', '-czf', archive_name, '-C', backup_dir, '.'],
        check=True
    )
    print(f'Backup erfolgreich erstellt: {archive_name}')
except subprocess.CalledProcessError as e:
    print(f'Fehler beim Backup: {e}')

Unter Windows könnten Sie stattdessen powershell-Befehle oder Compress-Archive verwenden.


Best Practices

  • Verwenden Sie subprocess.run() für einfache Aufrufe mit check=True, um Fehler sofort zu erkennen.
  • Nutzen Sie capture_output=True und text=True, wenn Sie Ausgaben in Python weiterverarbeiten wollen.
  • Vermeiden Sie shell=True, außer wenn komplexe Shell-Features benötigt werden.
  • Fangen Sie Ausnahmen wie subprocess.CalledProcessError ab, um Fehler gezielt zu behandeln.
  • Dokumentieren Sie externe Kommandos und deren erwartete Ergebnisse, um Wartbarkeit sicherzustellen.

Mit diesen Grundlagen können Sie externe Programme sicher und effektiv in Ihre Python-Automatisierung integrieren.

Systeminformationen ermitteln

Betriebssysteminformationen mit dem Modul platform

Das Python-Modul platform liefert grundlegende Informationen zum Betriebssystem und zur Hardware. Für Administratoren ist es wichtig, schnell zu erkennen, auf welchem System ein Skript läuft, um systemabhängige Befehle oder Pfade korrekt zu handhaben.

import platform

print("System:", platform.system())           # z.B. 'Linux' oder 'Windows'
print("Release:", platform.release())         # z.B. '5.15.0-58-generic' oder '10'
print("Version:", platform.version())         # detaillierte OS-Version
print("Maschine:", platform.machine())         # z.B. 'x86_64'
print("Prozessor:", platform.processor())       # z.B. 'Intel64 Family 6 Model 158'

Diese Informationen entsprechen in etwa den Ausgaben von uname -a unter Linux oder systeminfo in der Windows-Eingabeaufforderung.

Systeminformationen mit os und os.uname()

Unter Linux und Unix liefert os.uname() detaillierte Systemdaten:

import os

if hasattr(os, "uname"):
    uname = os.uname()
    print(f"System: {uname.sysname}")
    print(f"Node Name: {uname.nodename}")
    print(f"Release: {uname.release}")
    print(f"Version: {uname.version}")
    print(f"Machine: {uname.machine}")
else:
    print("os.uname() wird auf diesem System nicht unterstützt")

Unter Windows steht diese Funktion nicht zur Verfügung, hier ist platform die bessere Wahl.

Hardwareinformationen mit psutil

Für detaillierte Hardware- und Systemdaten ist das Drittanbieter-Modul psutil sehr hilfreich. Es ermöglicht den Zugriff auf CPU-Auslastung, Speichernutzung, Festplatteninformationen und mehr – wichtige Daten für Monitoring und Automatisierung.

Installation:

pip install psutil

Beispiel zur CPU- und Speicherabfrage:

import psutil

# CPU-Kerne
print(f"Logische CPU-Kerne: {psutil.cpu_count(logical=True)}")
print(f"Physische CPU-Kerne: {psutil.cpu_count(logical=False)}")

# CPU-Auslastung in Prozent
print(f"CPU-Auslastung (gesamt): {psutil.cpu_percent(interval=1)} %")

# Arbeitsspeicher
mem = psutil.virtual_memory()
print(f"Gesamter RAM: {mem.total / (1024 ** 3):.2f} GB")
print(f"Verfügbarer RAM: {mem.available / (1024 ** 3):.2f} GB")
print(f"RAM-Auslastung: {mem.percent} %")

# Festplattennutzung (Root-Partition)
disk = psutil.disk_usage("/")
print(f"Gesamter Speicher /: {disk.total / (1024 ** 3):.2f} GB")
print(f"Freier Speicher /: {disk.free / (1024 ** 3):.2f} GB")
print(f"Belegter Speicher /: {disk.percent} %")

Python-Laufzeitumgebung mit sys und platform

Neben Systeminformationen ist es oft wichtig, Details zur Python-Umgebung zu kennen, z.B. für Skripte, die plattformübergreifend laufen sollen.

import sys
import platform

print(f"Python-Version: {sys.version}")
print(f"Implementierung: {platform.python_implementation()}")
print(f"Interpreter-Pfad: {sys.executable}")

Praxis-Tipp: Systeminformationen für bedingte Logik nutzen

In Automatisierungsskripten ist es üblich, Betriebssystem-spezifische Befehle auszuführen. Ein einfaches Beispiel:

import platform
import subprocess

system = platform.system()

if system == "Linux":
    # Beispiel: Linux-spezifischer Befehl
    subprocess.run(["ls", "-l", "/var/log"])
elif system == "Windows":
    # Windows-spezifischer Befehl
    subprocess.run(["dir", "C:\\Windows\\System32"], shell=True)
else:
    print(f"Unbekanntes System: {system}")

Im Vergleich zu Shell-Skripten bietet Python mehr Flexibilität, z.B. bessere Fehlerbehandlung, plattformübergreifende Module und einfachere Integration in komplexe Automatisierungsabläufe.

Zusammenfassung

  • platform ist das Standardmodul für grundlegende Systeminformationen auf allen Plattformen.
  • os.uname() liefert unter Linux/Unix detaillierte Systemdaten.
  • psutil ermöglicht tiefe Einblicke in Hardware- und Systemzustände.
  • sys und platform helfen, die Python-Laufzeitumgebung zu erkennen.
  • Systeminformationen sind essenziell, um plattformabhängige Automatisierungen sicher und robust zu gestalten.

Diese Werkzeuge bilden die Basis, um mit Python verlässliche und wartbare Administrationsskripte zu schreiben, die auf verschiedenen Systemen konsistent funktionieren.

Netzwerk- und Prozessinformationen

Prozesse überwachen und analysieren

Für die Prozessverwaltung und -überwachung ist das Modul psutil das Standardwerkzeug in Python. Es ist plattformübergreifend und bietet umfassende Informationen zu laufenden Prozessen, CPU- und Speicherauslastung sowie Netzwerkverbindungen.

Zunächst installieren Sie psutil mit:

pip install psutil

Ein einfaches Beispiel, um alle laufenden Prozesse mit ihrer PID und dem Namen aufzulisten:

import psutil

for proc in psutil.process_iter(['pid', 'name']):
    print(f"PID: {proc.info['pid']}, Name: {proc.info['name']}")

Dies ist vergleichbar mit dem Befehl ps unter Linux oder Get-Process in PowerShell, aber mit der Flexibilität, die Ausgabe in Python weiterzuverarbeiten.

Prozesse gezielt filtern und Ressourcenverbrauch prüfen

Oft möchte man Prozesse mit hohem Ressourcenverbrauch finden, z. B. um Speicherfresser zu identifizieren:

for proc in psutil.process_iter(['pid', 'name', 'memory_actual_info']):
    mem = proc.info['memory_actual_info']
    if mem and mem.rss > 100 * 1024 * 1024:  # > 100 MB
        print(f"Hoher Speicherverbrauch: PID {proc.info['pid']} - {proc.info['name']} ({mem.rss / 1024 ** 2:.1f} MB)")

Netzwerkverbindungen und Ports auslesen

psutil erlaubt auch die Abfrage offener Netzwerkverbindungen, was für Sicherheitsüberprüfungen oder Monitoring wichtig ist:

for conn in psutil.net_connections(kind='inet'):
    laddr = f"{conn.laddr.ip}:{conn.laddr.port}" if conn.laddr else ""
    raddr = f"{conn.raddr.ip}:{conn.raddr.port}" if conn.raddr else "-"
    print(f"{conn.pid or '-':>5} {conn.status:>13} {laddr:>22} -> {raddr:>22}")

Dies entspricht unter Linux dem Befehl netstat -tunap oder ss, unter Windows netstat -ano.

Systemweite Netzwerkstatistiken

Neben einzelnen Verbindungen können Sie auch die gesamte Netzwerkauslastung abfragen:

net_io = psutil.net_io_counters()
print(f"Gesendete Bytes: {net_io.bytes_sent}")
print(f"Empfangene Bytes: {net_io.bytes_recv}")

Prozesse starten und steuern

Python erlaubt auch das Starten und Steuern von Prozessen, z. B. um externe Tools zu automatisieren:

import subprocess

# Beispiel: ping ausführen und Ausgabe lesen
result = subprocess.run(['ping', '-c', '3', '8.8.8.8'], capture_output=True, text=True)
print(result.stdout)

Im Gegensatz zu Shell-Skripten ermöglicht Python eine bessere Fehlerbehandlung und flexible Weiterverarbeitung der Ausgabe.

Best Practices

  • Verwenden Sie psutil für plattformübergreifende Prozess- und Netzwerkinfos.
  • Nutzen Sie Filter, um nur relevante Prozesse oder Verbindungen zu analysieren.
  • Kombinieren Sie Prozess- und Netzwerkdaten für umfassende Monitoring-Skripte.
  • Vermeiden Sie direkte Shell-Aufrufe, wenn Python-Module verfügbar sind, um Portabilität und Sicherheit zu erhöhen.

Zusammenfassung

Mit psutil und subprocess bietet Python leistungsfähige Werkzeuge, um Prozesse und Netzwerkstatus systematisch zu erfassen und zu steuern. Dies erleichtert die Automatisierung von Überwachungsaufgaben, Fehleranalysen und Infrastrukturmanagement erheblich – und zwar auf Linux und Windows gleichermaßen.