Prozesse und Systemzustand diagnostizieren, ohne ps oder top zu starten
Das virtuelle /proc-Dateisystem exportiert Kernel-Interna als scheinbare Dateien. Wer /proc/[pid]/status, /proc/meminfo und /proc/loadavg direkt mit Bash-Bordmitteln liest, baut leichtgewichtige Diagnose-Skripte, die ohne externen Prozessaufruf auskommen und in minimalen Container-Images ohne zusätzliche Werkzeuge funktionieren.
Inhaltsverzeichnis
- 1. Was /proc wirklich ist: ein virtuelles Fenster in den Kernel
- 2. /proc/[pid]/status auslesen: Prozesszustand ohne ps
- 3. /proc/meminfo: Speicherdiagnose direkt aus Bash
- 4. /proc/loadavg: Systemlast auslesen und richtig interpretieren
- 5. /proc/[pid]/fd: offene Dateideskriptoren eines Prozesses zählen
- 6. Ein eigenes Diagnose-Skript bauen: Health-Check ohne externe Tools
- 7. Performance: /proc lesen im Vergleich zu ps oder top aufrufen
- 8. Portabilitätsgrenzen: /proc funktioniert nur unter Linux
- 9. Sicherheits- und Berechtigungsaspekte beim Lesen von /proc
- 10. Zusammenfassung
- 11. FAQ
1. Was /proc wirklich ist: ein virtuelles Fenster in den Kernel
/proc ist kein normales Dateisystem mit Dateien auf einer Platte, sondern eine virtuelle Schnittstelle, über die der Linux-Kernel interne Datenstrukturen als scheinbare Dateien exportiert. Ein cat /proc/meminfo liest keine Datei im klassischen Sinn, sondern löst im Kernel eine Funktion aus, die den aktuellen Speicherzustand in Textform generiert und sofort wieder verwirft, sobald der Lesevorgang beendet ist.
Für ein Bash-Skript bedeutet das einen entscheidenden Vorteil gegenüber dem Aufruf externer Kommandos wie ps oder free: Das Lesen einer /proc-Datei mit den eingebauten Bash-Mitteln startet keinen zusätzlichen Prozess, spart also den Overhead von fork und exec komplett. Bei Diagnose-Skripten, die häufig und in kurzen Intervallen laufen, etwa in einem Monitoring-Loop, macht dieser Unterschied messbar aus, wie viel zusätzliche Last das Skript selbst erzeugt.
2. /proc/[pid]/status auslesen: Prozesszustand ohne ps
Die Datei /proc/[pid]/status enthält für jeden laufenden Prozess ein für Menschen lesbares Schlüssel-Wert-Format mit Feldern wie Name, State, VmRSS für den tatsächlich genutzten physischen Speicher und Threads für die Anzahl laufender Threads. Ein Bash-Skript kann diese Werte mit einfachem Parsing extrahieren, ohne ps mit seinen zahlreichen Formatierungsoptionen aufrufen zu müssen.
Besonders nützlich für Diagnose-Skripte ist das Feld State, das den exakten Prozesszustand als einzelnen Buchstaben liefert, etwa R für laufend, S für schlafend oder Z für Zombie. Ein Skript, das regelmäßig prüfen soll, ob ein Dienst tatsächlich noch aktiv arbeitet statt nur als Zombie in der Prozesstabelle zu hängen, liest genau dieses Feld, statt sich auf die bloße Existenz des PIDs in /proc zu verlassen.
pid=$(pgrep -f "my-worker.sh" | head -n1)
if [[ -r "/proc/$pid/status" ]]; then
state=$(awk '/^State:/{print $2}' "/proc/$pid/status")
rss_kb=$(awk '/^VmRSS:/{print $2}' "/proc/$pid/status")
echo "PID $pid: Status=$state, RSS=${rss_kb} KB"
fi
3. /proc/meminfo: Speicherdiagnose direkt aus Bash
/proc/meminfo liefert eine detaillierte Übersicht des Systemspeichers in Kilobyte, unter anderem MemTotal, MemFree und MemAvailable. Gerade MemAvailable ist für Diagnose-Skripte der zuverlässigste Wert, weil er im Gegensatz zu MemFree bereits berücksichtigt, dass der Kernel Caches bei Bedarf sofort freigeben kann, ohne dass Anwendungen wirklich unter Speicherdruck geraten.
Ein Diagnose-Skript, das vor einem Deployment prüfen soll, ob genug freier Speicher für einen kurzzeitigen Speicherpeak vorhanden ist, liest MemAvailable direkt aus /proc/meminfo und vergleicht den Wert gegen einen Schwellenwert, statt das schwerer zu interpretierende Ausgabeformat von free zu parsen. Da beide Werte letztlich aus derselben Kernel-Quelle stammen, liefert der direkte /proc-Zugriff exakt dieselben Zahlen, nur ohne den Umweg über einen externen Prozess.
mem_available_kb=$(awk '/^MemAvailable:/{print $2}' /proc/meminfo)
threshold_kb=$((512 * 1024))
if (( mem_available_kb < threshold_kb )); then
echo "WARNUNG: nur ${mem_available_kb} KB verfuegbar" >&2
exit 1
fi
echo "OK: ${mem_available_kb} KB verfuegbar"
4. /proc/loadavg: Systemlast auslesen und richtig interpretieren
/proc/loadavg enthält die durchschnittliche Systemlast über die letzten 1, 5 und 15 Minuten als drei Fließkommazahlen, gefolgt von der Anzahl aktuell laufender gegenüber der Gesamtzahl an Prozessen und der PID des zuletzt erzeugten Prozesses. Diese Werte entsprechen exakt dem, was top oder uptime am oberen Bildschirmrand anzeigen, direkt aus derselben Kernel-Quelle gelesen.
Für eine sinnvolle Interpretation muss die Load-Average immer in Relation zur Anzahl der CPU-Kerne gesetzt werden, die sich mit nproc ermitteln lässt. Eine Load von 4 ist auf einer 8-Kern-Maschine unauffällig, auf einer 2-Kern-Maschine dagegen ein deutliches Warnsignal für Überlast. Ein robustes Diagnose-Skript berechnet deshalb immer das Verhältnis aus Load und Kernanzahl, statt einen festen absoluten Schwellenwert zu verwenden, der auf unterschiedlicher Hardware falsche Alarme oder verpasste Warnungen erzeugt.
load_1min=$(awk '{print $1}' /proc/loadavg)
cores=$(nproc)
ratio=$(awk -v l="$load_1min" -v c="$cores" 'BEGIN{printf "%.2f", l/c}')
echo "Load: $load_1min, Kerne: $cores, Verhaeltnis: $ratio"
5. /proc/[pid]/fd: offene Dateideskriptoren eines Prozesses zählen
Das Verzeichnis /proc/[pid]/fd enthält für jeden offenen Dateideskriptor eines Prozesses einen symbolischen Link, der auf die geöffnete Datei, den Socket oder die Pipe zeigt. Die Anzahl der Einträge in diesem Verzeichnis entspricht damit exakt der Anzahl aktuell offener Deskriptoren, ein Wert, der bei Datei-Leck-Diagnosen wichtiger ist als jede Log-Ausgabe der Anwendung selbst.
Ein Diagnose-Skript, das einen Prozess über die Zeit beobachtet und die Anzahl der Einträge in /proc/[pid]/fd protokolliert, deckt Datei-Leaks auf, lange bevor der Prozess an das per ulimit gesetzte Limit für offene Dateien stößt und mit "Too many open files" abbricht. Steigt die Anzahl kontinuierlich ohne erkennbaren Zusammenhang mit der tatsächlichen Last, ist das ein zuverlässiges Frühwarnsignal für ein Leck in der überwachten Anwendung.
pid=$(pgrep -f "my-app" | head -n1)
fd_count=$(ls "/proc/$pid/fd" 2>/dev/null | wc -l)
echo "PID $pid hat $fd_count offene Deskriptoren"
6. Ein eigenes Diagnose-Skript bauen: Health-Check ohne externe Tools
Die gezeigten Bausteine lassen sich zu einem kompakten Health-Check-Skript zusammensetzen, das ohne ps, free oder top auskommt und ausschließlich mit Bash-Bordmitteln arbeitet. Ein solches Skript eignet sich besonders für minimale Container-Images, in denen bewusst keine zusätzlichen Diagnose-Werkzeuge installiert sind, weil jedes zusätzliche Paket die Angriffsfläche und die Image-Größe vergrößert.
Der Vorteil eines reinen /proc-basierten Health-Checks zeigt sich besonders in Kubernetes-Liveness-Probes, die häufig in Sekundenabständen laufen: Ein Skript ohne externe Prozessaufrufe verursacht spürbar weniger CPU-Last als eines, das bei jedem Durchlauf ps oder free startet, was bei tausenden gleichzeitig laufenden Pods durchaus messbar ins Gewicht fällt.
#!/usr/bin/env bash
set -euo pipefail
pid=$$
mem_kb=$(awk '/^MemAvailable:/{print $2}' /proc/meminfo)
load=$(awk '{print $1}' /proc/loadavg)
fd_count=$(ls "/proc/$pid/fd" | wc -l)
echo "mem_available_kb=$mem_kb load_1min=$load own_fds=$fd_count"
7. Performance: /proc lesen im Vergleich zu ps oder top aufrufen
Der Aufruf eines externen Kommandos wie ps kostet in Bash immer einen fork- und exec-Syscall, das Anlegen eines neuen Prozessabbilds und häufig das Laden dynamischer Bibliotheken, selbst wenn die eigentliche Arbeit von ps nur wenige Millisekunden dauert. Das direkte Lesen einer /proc-Datei mit Bash-Bordmitteln umgeht diesen kompletten Overhead und bleibt innerhalb desselben Prozesses.
Bei einem einzelnen Diagnose-Aufruf ist dieser Unterschied kaum spürbar, bei einem Monitoring-Skript, das im Sekundentakt läuft und dabei mehrere externe Kommandos verkettet, summiert sich der Overhead spürbar auf, gerade auf ressourcenbeschränkten Systemen wie kleinen Cloud-Instanzen oder eingebetteten Geräten. Wer Diagnose-Skripte für genau solche Umgebungen schreibt, sollte externe Prozessaufrufe konsequent durch direkte /proc-Zugriffe ersetzen, wo immer das möglich ist.
8. Portabilitätsgrenzen: /proc funktioniert nur unter Linux
/proc ist eine Linux-spezifische Kernel-Schnittstelle, die auf macOS und den BSD-Varianten schlicht nicht existiert. Skripte, die direkt auf /proc/meminfo oder /proc/loadavg zugreifen, scheitern auf einem Mac sofort mit einem Datei-nicht-gefunden-Fehler, weil macOS Systeminformationen über völlig andere Mechanismen wie sysctl bereitstellt.
Wer ein Diagnose-Skript für mehrere Plattformen schreiben muss, sollte deshalb entweder konsequent auf portable Kommandos wie vm_stat auf macOS und /proc unter Linux mit einer Fallunterscheidung über uname -s zurückgreifen, oder von vornherein akzeptieren, dass ein rein /proc-basiertes Skript ausschließlich für Linux-Server gedacht ist, was in reinen Docker- und Kubernetes-Deployment-Kontexten ohnehin fast immer der Fall ist.
9. Sicherheits- und Berechtigungsaspekte beim Lesen von /proc
Ein Prozess kann grundsätzlich nur die vollständigen Details von /proc/[pid] für Prozesse desselben Benutzers lesen, für fremde Prozesse liefert der Kernel je nach Feld entweder eingeschränkte oder gar keine Informationen, sofern der lesende Prozess nicht mit erhöhten Rechten läuft. Ein Diagnose-Skript, das als normaler Nutzer läuft, sieht deshalb typischerweise nur die eigenen Prozesse vollständig.
Diagnose-Skripte, die als root laufen, um systemweite Informationen zu sammeln, sollten diese erhöhten Rechte bewusst und minimal einsetzen, etwa über eine dedizierte Capability statt eines vollständigen root-Kontexts, und niemals Werte aus /proc ungeprüft in weitere Kommandos einsetzen, weil manipulierte Prozessnamen theoretisch zu Command-Injection führen könnten, wenn sie ohne Quoting in einen weiteren Shell-Aufruf eingebettet werden.
| Quelle | Liefert | Nur Linux | Benötigt Root |
|---|---|---|---|
| /proc/[pid]/status | Prozesszustand, Speicher, Threads | Ja | Nein, für eigene Prozesse |
| /proc/meminfo | Systemweiter Speicherstatus | Ja | Nein |
| /proc/loadavg | Systemlast über 1/5/15 Minuten | Ja | Nein |
| /proc/[pid]/fd | Offene Dateideskriptoren zählen | Ja | Nein, für eigene Prozesse |
| ps/top (Vergleich) | Ähnliche Daten, externer Prozess | Nein, portabel | Nein |
Mironsoft
Shell-Automatisierung, DevOps-Tooling und Deployment-Infrastruktur
Shell-Skripte, die in der Produktion zuverlässig laufen?
Wir analysieren bestehende Bash-Skripte, erkennen fragile Muster und ersetzen sie durch robuste Bash-Patterns: mit vollständiger Fehlerbehandlung, Logging und sicherer Parallelisierung für euren Deployment-Stack.
Code-Review
ShellCheck-Analyse und manuelle Prüfung auf kritische Bash-Pattern-Verstöße.
Refactoring
Fehlerbehandlung, Logging und sichere Dateioperationen nachrüsten.
CI-Integration
ShellCheck und BATS in Pipelines integrieren und Regressionstests aufbauen.
10. Zusammenfassung
/proc-Dateisystem in Bash: Das Wichtigste auf einen Blick
Kein externer Prozess
Direktes Lesen von /proc-Dateien mit Bash-Bordmitteln spart fork und exec gegenüber ps oder free.
Wichtigste Quellen
/proc/[pid]/status, /proc/meminfo und /proc/loadavg decken Prozesszustand, Speicher und Systemlast ab.
Nur Linux
/proc existiert nicht auf macOS oder BSD, Skripte für mehrere Plattformen brauchen eine Fallunterscheidung.
Berechtigungen beachten
Fremde Prozessdetails sind meist eingeschränkt, Werte aus /proc nie ungeprüft in weitere Kommandos einsetzen.