ps (process status) ist das klassische Werkzeug, um zu sehen, was gerade auf einem Linux-System läuft. Anders als top oder htop liefert ps keinen Live-Stream, sondern einen Snapshot zum Zeitpunkt des Aufrufs — eine Zeile pro Prozess, einmal eingefroren. Das macht ps ideal für Skripte, Pipes, schnelle Übersichten und gezielte Filter.
Was ps macht
ps fragt den Kernel über /proc ab und gibt eine Liste aller (oder gefilterter) Prozesse aus — mit PID, Eigentümer, CPU-/Speicher-Nutzung, Status und Befehlszeile. Die Ausgabe ist statisch: Was du siehst, ist der Stand zum Zeitpunkt des Aufrufs. Wer fortlaufende Updates will, nutzt top, htop oder kombiniert ps mit watch.
ps selbst ist Teil des procps-Pakets (heute meistens procps-ng) und auf praktisch jedem Linux-System vorhanden. Auf BSD und macOS gibt es eine eigene Variante mit teils abweichender Semantik — was bei ps zu den berüchtigten Optionen-Mehrdeutigkeiten führt.
ps PID TTY TIME CMD
3421 pts/0 00:00:00 bash
4187 pts/0 00:00:00 psOhne Optionen zeigt ps nur die Prozesse der aktuellen Shell-Session — meistens wenig spannend. Erst die Optionen machen ps nützlich.
Drei Optionen-Stile
ps ist historisch gewachsen und vereint drei Welten in einem Befehl. Welche Schreibweise du nutzt, ist Geschmack — wichtig ist, dass du die Unterschiede kennst, weil sie sich teils sehr unterschiedlich verhalten.
| Stil | Schreibweise | Beispiel | Herkunft |
|---|---|---|---|
| UNIX | mit Bindestrich | ps -ef | POSIX / SysV |
| BSD | ohne Bindestrich | ps aux | BSD-Tradition |
| GNU long | doppelter Bindestrich | ps --forest | GNU-Erweiterungen |
Mischen ist erlaubt, kann aber verwirrend werden — ps -aux ist nicht dasselbe wie ps aux, dazu mehr in den Stolperfallen. Im Alltag haben sich zwei Varianten als „Standard” etabliert: ps aux (BSD) und ps -ef (UNIX). Welche du nimmst, ist meistens reine Gewohnheit.
Standard-Patterns: aux und -ef
Beide Aufrufe zeigen alle Prozesse aller Benutzer — der Unterschied liegt in den Default-Spalten und in einigen Details.
ps auxUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 168432 11892 ? Ss May03 0:04 /sbin/init
root 412 0.0 0.0 47120 5984 ? Ss May03 0:01 /lib/systemd/systemd-journald
michael 3421 0.0 0.0 21344 5120 pts/0 Ss 09:11 0:00 -bash
michael 4187 0.0 0.0 19112 3712 pts/0 R+ 09:42 0:00 ps auxEine Zeile pro Prozess: Eigentümer, PID, aktuelle CPU- und Speicher-Auslastung in Prozent, virtueller und residenter Speicher in Kilobytes, das kontrollierende Terminal, der Status-Code, Startzeit, kumulierte CPU-Zeit und der vollständige Aufruf.
ps -efUID PID PPID C STIME TTY TIME CMD
root 1 0 0 May03 ? 00:00:04 /sbin/init
root 412 1 0 May03 ? 00:00:01 /lib/systemd/systemd-journald
michael 3421 3418 0 09:11 pts/0 00:00:00 -bash
michael 4188 3421 0 09:42 pts/0 00:00:00 ps -ef-ef zeigt zusätzlich die PPID (Parent-PID) und macht damit die Eltern-Kind-Beziehungen sichtbar. Dafür fehlen %CPU, %MEM, VSZ und RSS — die sind eher der Stärken-Bereich von aux. Wer Hierarchie sehen will, nimmt -ef (oder direkt --forest); wer Ressourcen-Verbrauch sehen will, nimmt aux.
Spalten interpretieren
Die wichtigsten Spalten und was sie bedeuten:
| Spalte | Bedeutung |
|---|---|
| UID / USER | Eigentümer des Prozesses |
| PID | Process ID, eindeutige Nummer pro laufendem Prozess |
| PPID | Parent Process ID, der Prozess, der diesen gestartet hat |
| %CPU | Anteil CPU-Zeit seit Prozessstart, gemittelt |
| %MEM | Anteil RSS am gesamten physischen RAM |
| VSZ | Virtual Size in KiB, der gesamte adressierbare Speicher |
| RSS | Resident Set Size in KiB, tatsächlich im RAM gehaltener Anteil |
| TTY | kontrollierendes Terminal, ? bei Daemons ohne TTY |
| STAT | Prozess-Status mit Modifiern, siehe nächste Sektion |
| START / STIME | Startzeitpunkt des Prozesses |
| TIME | bisher verbrauchte CPU-Zeit (kumuliert) |
| CMD / COMMAND | aufgerufener Befehl mit Argumenten |
VSZ und RSS werden gerne verwechselt: VSZ ist der gesamte virtuelle Adressraum eines Prozesses — inklusive gemappter Bibliotheken, ungenutzter Allokationen und shared Memory. RSS ist der Anteil davon, der gerade tatsächlich im physischen RAM liegt. Für „wie viel RAM verbraucht der Prozess?” ist RSS die ehrlichere Antwort, wobei auch das durch shared Pages noch über die Realität liegen kann.
STAT-Codes
Die STAT-Spalte besteht aus einem Hauptstatus und optionalen Modifiern. Den Hauptteil kennst du aus dem Prozess-Modell, die Modifier kommen hinzu.
| Code | Bedeutung | Typ |
|---|---|---|
R | running oder runnable (auf der CPU oder in der Run-Queue) | Hauptstatus |
S | interruptible sleep (wartet auf Ereignis, weckbar) | Hauptstatus |
D | uninterruptible sleep (meistens auf I/O) | Hauptstatus |
T | gestoppt (SIGSTOP, SIGTSTP oder Tracer) | Hauptstatus |
Z | zombie (beendet, aber Eltern hat noch nicht wait() aufgerufen) | Hauptstatus |
< | erhöhte Priorität (negativer Nice-Wert) | Modifier |
N | reduzierte Priorität (positiver Nice-Wert) | Modifier |
+ | im Vordergrund einer Prozessgruppe | Modifier |
s | Session Leader | Modifier |
l | multi-threaded (verwendet Kernel-Threads) | Modifier |
L | hat Pages im Speicher gelockt | Modifier |
Ss ist also „interruptible sleeping session leader” — typisch für Daemons. R+ ist „läuft im Vordergrund” — typisch für ein gerade gestartetes Kommando. Z ohne weiteres ist immer ein Hinweis auf einen Zombie, den jemand einsammeln müsste.
Custom-Output mit -o
Mit -o legst du selbst fest, welche Spalten erscheinen. Das ist die Königsdisziplin von ps: Du bekommst genau die Daten, die du brauchst, in der Reihenfolge, die du willst — perfekt für Pipes und Skripte.
ps -eo pid,user,stat,start,cmd --sort=-%cpu PID USER STAT STARTED CMD
2912 michael Sl May03 /usr/lib/firefox/firefox
3187 michael Sl May03 /usr/bin/code --no-sandbox
1 root Ss May03 /sbin/init
4192 michael R+ 09:43 ps -eo pid,user,stat,start,cmd --sort=-%cpu-e heißt „alle Prozesse” (wie das a in aux), -o legt das Format fest, --sort=-%cpu sortiert absteigend (das Minus-Zeichen kehrt um). Eine vollständige Liste aller verfügbaren Format-Specifier liefert ps L:
ps LHäufig genutzte Specifier sind pid, ppid, pgid, sid, user, uid, pcpu, pmem, rss, vsz, stat, start, time, etime (Laufzeit seit Start), comm (nur Prozessname) und cmd (komplette Kommandozeile).
Filter und Sortieren
Statt erst alles auszugeben und dann mit grep zu filtern, kann ps direkt einschränken — sauberer und in Skripten robuster.
ps -u michaelps -p 1,412,3421ps -C bash-C matcht den Prozessnamen (also den comm-Wert, nicht die volle Kommandozeile), mehrere Namen kommagetrennt. Für Sortierung nutzt du --sort= mit einem Specifier — Minus-Zeichen kehrt die Richtung um:
ps aux --sort=-rssps -eo pid,etime,cmd --sort=etimeAlternativ funktioniert auch klassisch via Pipe (ps aux | sort -k 4 -nr), das ist aber fehleranfälliger als --sort direkt in ps.
Praxis-Patterns
Diese Aufrufe braucht man im Alltag immer wieder — als Aliases oder im Muskelgedächtnis nützlich.
ps aux --sort=-%cpu | headSortiert alle Prozesse absteigend nach CPU-Anteil und schneidet die Top 10 ab. Schnellste Antwort auf „Wer frisst gerade meine CPU?” — wobei der Wert über die Lebenszeit des Prozesses gemittelt ist, also kurze Spitzen zeigt top besser.
ps aux --sort=-%mem | headDasselbe für Speicher. Browser, Java-Prozesse und Datenbanken landen hier fast immer in der Spitzengruppe. Für genauere Aussagen über tatsächlich „verbrauchten” RAM lohnt zusätzlich ein Blick auf smem oder /proc/PID/status.
ps -ef --forest--forest zeichnet die Eltern-Kind-Struktur als ASCII-Baum direkt in die CMD-Spalte. Praktisch, um Daemon-Trees (systemd -> Service -> Worker) oder Shell-Hierarchien (Terminal -> Shell -> gestartete Programme) zu verstehen.
ps -u $USERFiltert auf den aktuellen Login-User. Auf Mehrbenutzer-Systemen oder Servern oft das Erste, was man sehen will, bevor man nach root-Prozessen sucht.
pgrep -a sshdpgrep ist der spezialisierte Bruder von ps: Er sucht Prozesse nach Name oder Muster und gibt nur PIDs (oder mit -a zusätzlich die Kommandozeile) aus. Für Skripte ist pgrep fast immer eleganter als ps ... | grep ... | awk ....
Stolperfallen
aux und -aux sind nicht dasselbe
Klassische Verwechslung: ps aux ist BSD-Stil und zeigt alle Prozesse aller User mit Detailspalten. ps -aux ist UNIX-Stil und sollte streng genommen „alle Prozesse von User x” bedeuten — moderne procps-Versionen geben dafür eine Warnung aus und behandeln den Aufruf wie aux, aber verlassen darf man sich darauf nicht. Merksatz: Im BSD-Stil keine Bindestriche.
ps zeigt nur einen Snapshot
ps friert den Zustand zum Zeitpunkt des Aufrufs ein. Kurze Spitzen, kurzlebige Prozesse oder ein sich ändernder STAT bleiben unsichtbar. Für Live-Beobachtung ist top/htop die richtige Wahl, oder watch -n 1 ‘ps aux —sort=-%cpu | head’, um den Snapshot regelmäßig neu zu zeichnen.
Threads vs. Prozesse
Standardmäßig zeigt ps nur Prozesse, keine einzelnen Threads. Mehrgewichtige Programme (Browser, JVM, Datenbanken) erscheinen als ein Eintrag, obwohl intern Dutzende Threads laufen. Mit -T oder -L bekommst du eine Zeile pro Thread inklusive SPID/LWP. Sichtbar wird das auch im STAT-Modifier l (lower-case L) für „multi-threaded”.
CMD wird in Default-Breite abgeschnitten
Lange Kommandozeilen schneidet ps auf die Terminal-Breite zu — was beim Debuggen genau die Information versteckt, die du brauchst. Mit -w bekommst du eine breitere Ausgabe, mit -ww wird die Kommandozeile gar nicht mehr abgeschnitten. In Pipes (also wenn das Ausgabe-Ziel kein Terminal ist) erkennt ps das oft selbst, aber sicher ist -ww.
START-Format wechselt für ältere Prozesse
Solange ein Prozess am gleichen Tag gestartet wurde, zeigt ps die Uhrzeit (09:42). Älter als 24 Stunden, kommt das Datum (May03); noch älter, das Jahr. Für reproduzierbare Ausgaben in Skripten lieber explizit -o lstart oder etime nutzen — die liefern ein stabiles Format.
VSZ ist nicht der reale Speicherverbrauch
Ein Prozess kann ein VSZ von 2 GiB haben und trotzdem nur 50 MiB physischen RAM (RSS) belegen — der Rest sind ungenutzte virtuelle Adressen, gemappte Libraries oder Shared Memory. Wer „wie viel RAM frisst Prozess X?” beantworten will, schaut auf RSS, idealerweise mit Tools wie smem, die zusätzlich Shared Pages berücksichtigen.
Zombies erkennt man an STAT=Z
Ein Prozess im Status Z ist beendet, sein Exit-Status wartet aber noch im Kernel auf wait() durch den Eltern-Prozess. Zombies belegen kaum Ressourcen (nur einen Eintrag in der Prozess-Tabelle), aber viele davon weisen auf einen Bug im Eltern-Prozess hin. Killen lassen sie sich nicht direkt — der Eltern-Prozess muss reagieren oder selbst beendet werden, dann erbt init die Zombies und räumt auf.
ps selbst taucht in der Liste auf
Wer ps aux | grep firefox schreibt, sieht in der Ausgabe oft auch die grep-Zeile selbst, weil grep firefox ja den String „firefox” enthält. Klassischer Trick: ps aux | grep [f]irefox — die Zeichenklasse matcht zwar das gleiche, aber im ps-Output steht [f]irefox wörtlich, nicht firefox, und fällt durchs Filter. Sauberer ist von Anfang an pgrep -a firefox.
Weiterführende Ressourcen
Externe Quellen
- ps(1) – Manpage (man7.org) — Vollständige Optionsreferenz mit allen Stilen
- procps-ng auf GitLab — Quellprojekt von
ps,top,pgrepund Verwandten - Arch Wiki: Core utilities — Übersicht zu
psund benachbarten Tools - Linux Kernel: /proc Filesystem — Worauf
psintern zugreift - Brendan Gregg: Linux Performance —
psim Kontext von Performance-Tools
Verwandte Artikel
- Prozess-Modell — PID, PPID, Status-Codes und Lebenszyklus
- top — Live-Monitor als Live-Pendant zu
ps - htop — Interaktiver Prozess-Browser mit Tree-Ansicht
- kill — Prozesse beenden, sobald die PID via
psgefunden ist - Signale — Was hinter
SIGSTOP,SIGTERMund Co. steckt