HOWTO zum Exit-Status von Kommandos
===================================

(C) 2006-2026 T.Birnthaler/H.Gottschalk <howtos(at)ostc.de>
              OSTC Open Source Training and Consulting GmbH
              www.ostc.de

$Id: shell-exit-code-HOWTO.txt,v 1.11 2026/06/09 17:19:15 tsbirn Exp $

Dieses Dokument beschreibt die Bedeutung des Shell-Exit-Status und seine
Nutzung in Shell-Skripten, um den Ablauf in Abhängigkeit vom Ergebnis eines
Kommandos zu steuern.

Jedes Kommando (jeder Prozess) gibt am Ende einen "Exit-Status" (kleiner Wert
im Bereich 0-255) zurück, über den es seinem Elternprozeß mitteilt, ob es
korrekt ablief oder ob ein Fehler auftrat.

  +------------+--------------------------------------------------------+
  | Code       | Bedeutung                                              |
  +------------+--------------------------------------------------------+
  | 0          | Kommando lief korrekt ab                               |
  | ungleich 0 | Bei der Ausführung des Kommandos trat ein FEHLER auf   |
  |            | (Wert kann die FEHLERART beschreiben, muss aber nicht) |
  +------------+--------------------------------------------------------+

HINWEIS: Die Bedeutung der einzelnen Exit-Fehlercodes ist von Kommando zu
Kommando VERSCHIEDEN und kann in der jeweiligen man-Page nachgelesen werden
(nach dem Begriff "exit status" suchen, er wird oft erst am Ende erläutert).

Der Exit-Status kann NUR DIREKT NACH einem Kommando abgefragt und über das
Kommando "test" für Verzweigungen des Programmflusses benutzt werden. Er steht
auch in der Shell-Variablen "$?" (bzw. "$status" bei der (t)csh) und kann
darüber ausgegeben werden. Beispiele:

  grep TEXT FILE   # 0 falls TEXT (Muster) in FILE gefunden
                   # 1 falls TEXT (Muster) in FILE nicht gefunden
                   # 2 falls FILE nicht vorhanden oder TEXT (Muster) fehlerhaft
  echo $?          # Exit-Status ausgeben (nur 1x sinnvoll, da "echo" auch Kmdo.)
  echo $?          # Exit-Status von vorherigem "echo" (Wert "0" da erfolgreich)
  grep TEXT FILE   # 0 falls TEXT (Muster) in FILE gefunden
  ES=$?            # Exit-Status in Variable ES speichern (für mehrfachen Vgl.)

Da für die Shell der Wert 0 "logisch wahr" bedeutet und alle anderen Werte 1,
2, ... für sie "logisch falsch" bedeuten, kann über den Exit-Status eines Tests
per "[...]" oder "test" der Ablauf eines Shell-Skriptes gesteuert werden:

  [ -f /tmp/text ] && echo "Datei '/tmp/text' existiert"
  [ -d /tmp/dir  ] || echo "Verzeichnis '/tmp/dir' existiert nicht"

Da jedes Kommando/Programm/Skript einen Exit-Status erzeugt, kann sein Erfolg
anschließend sofort überprüft und entsprechend reagiert werden (die
Fehlermeldungen per "echo" wird dabei auf "stderr" (1>&2) ausgegeben):

  grep "error:" /tmp/log > /dev/null && echo "Fehler in Log gefunden" 1>&2
  mv text /tmp || echo "Datei 'text' nicht verschiebbar" 1>&2
  chmod a+w log || echo "Rechte von Datei 'log' nicht änderbar" 1>&2

  if grep "error:" /tmp/log > /dev/null
  then
      echo "$(grep -c "error:" /tmp/log > /dev/null) Fehler in Log gefunden"
  else
      echo "Alles in Ordnung"
  fi

Meist interessiert in einem Shell-Skript die Ausgabe eines Kommandos überhaupt
nicht, sondern nur der Exit-Status. D.h. beim Kommando-Aufruf wirft man alle
Ausgaben per Umleitung mit einer der folgenden drei Möglichkeiten weg:

  if grep "error:" /tmp/log > /dev/null 2> /dev/null; ...
  if grep "error:" /tmp/log > /dev/null 1>&2; ...
  if grep "error:" /tmp/log >& /dev/null; ...

Die Shell (bash, ksh) selbst kennt zwei Exit-Status mit denen sie den
fehlgeschlagenen Aufruf eines Kommandos kommuniziert:

  +-------------+-------------------------------------------------+
  | Exit-Status | Bedeutung                                       |
  +-------------+-------------------------------------------------+
  | 126         | Kommando gefunden, aber nicht lesbar/ausführbar |
  | 127         | Kommando nicht gefunden                         |
  +-------------+-------------------------------------------------+

Beim Abbruch eines Kommandos per SIGNAL wird die Signal-Nummer + 128 als
Exit-Status zurückgegeben:

  +----------------+------------+---------+---------------+
  | ES = 128 + Sig | Bedeutung  | Name    | Steuerzeichen |
  +----------------+------------+---------+---------------+
  | 129 = 128 +  1 | Hangup     | SIGHUP  | Strg-D        |
  | 130 = 128 +  2 | Interrrupt | SIGINT  | Strg-C        |
  | 131 = 128 +  3 | Quit       | SIGQUIT |               |
  | 134 = 128 +  6 | Abort      | SIGABRT |               |
  | 137 = 128 +  9 | Kill       | SIGKILL |               |
  | 138 = 128 + 10 | User 1     | SIGUSR1 |               |
  | 140 = 128 + 12 | User 2     | SIGUSR2 |               |
  | 141 = 128 + 13 | Pipe       | SIGPIPE |               |
  | 142 = 128 + 14 | Alarm      | SIGALRM |               |
  | 143 = 128 + 15 | Terminate  | SIGTERM |               |
  | 145 = 128 + 17 | Child      | SIGCHLD |               |
  | 146 = 128 + 18 | Continue   | SIGCONT | Strg-Q        |
  | 147 = 128 + 19 | Stop       | SIGSTOP | Strg-S        |
  | 148 = 128 + 20 | Typed Stop | SIGTSTP | Strg-Z        |
  +----------------+------------+---------+---------------+