HOWTO zum Test von Bedingungen in Shell-Skripten

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

$Id: shell-test-HOWTO.txt,v 1.9 2025/02/18 10:08:31 tsbirn Exp $

Dieses Dokument beschreibt die verschiedenen Möglichkeiten, die das Kommando
"test" bzw. "[...]" bzw. "[[...]]" zum Bedingungs-Test in der Shell bietet.

Inhaltsverzeichnis

1) Das Kommando "test"
2) Mit "test" überprüfbare Bedingungen
2.1) Nur in der Bash vorhandene Bedingungen
2.2) Nur in [[...]] vorhandene Bedingungen

1) Das Kommando "test"   (Toc)

Das Kommando "test" überprüft eine Bedingung, die ihm in Form von Argumenten
mitgegeben wird und gibt folgende Exit-Stati zurück:

  +---+------------------------------------+
  | 0 | Bedingung erfüllt ("wahr")         |
  | 1 | Bedingung NICHT erfüllt ("falsch") |
  | 2 | Syntaxfehler                       |
  +---+------------------------------------+

Die Syntax des "test"-Kommandos lautet (Kommando "[" ist Link auf "test"):

  test COND ...     # Kommando-Form
  [ COND ] ...      # Leerzeichen um eckige Klammern notwendig (analog "test")
  [[ COND ]] ...    # Leerzeichen um eckige Klammern notwendig (modern, kann mehr)

Das Kommando "test" wird zusammen mit "if", "while", "&&" und "||" verwendet.

2) Mit "test" überprüfbare Bedingungen   (Toc)

Folgende Bedingungen COND sind möglich, die einzelnen Elemente einer Bedingung
müssen mit Leerzeichen getrennt werden:

* Dateiexistenz- und Dateigröße-Vergleich:

  -e FILE            # Datei FILE existiert [exists]
  -s FILE            # Datei FILE existent und NICHT leer [size]
  \! -s FILE         # Datei FILE existent und leer [not size]

* Dateityp-Vergleich (gleichzeitig Existenz-Test!):

  -f FILE            # Datei FILE normale Datei [file]
  -d FILE            # Datei FILE [directory]
  -b FILE            # Datei FILE blockorientiert [block device]
  -c FILE            # Datei FILE zeichenorientiert [character device]
  -L FILE            # Datei FILE ein symbolischer Link [link]
  -p FILE            # Datei FILE eine Named Pipe/FIFO [pipe]
  -S FILE            # Datei FILE ein Socket [socket]
  -t FILE            # Datei FILE ein Terminal [terminal]

* Dateirechte-Vergleich:

  -r FILE            # Datei FILE lesbar [readable]
  -w FILE            # Datei FILE schreibbar [writable]
  -x FILE            # Datei FILE ausführbar [executable]
  -g FILE            # Datei FILE hat Group-ID Recht gesetzt [group]
  -k FILE            # Datei FILE hat Sticky-Bit gesetzt [sticky]
  -u FILE            # Datei FILE hat User-ID Recht gesetzt [user]

* Text-Vergleich:

  "TEXT"             # TEXT NICHT leer (nicht mit !/-a/-o kombinierbar!)
  -n "TEXT"          # TEXT NICHT leer (mit !/-a/-o kombinierbar!) [nonzero]
  -z "TEXT"          # TEXT leer [zero]
  "TEXT1" = "TEXT2"  # TEXT1 und TEXT2 gleich
  "TEXT1" != "TEXT2" # TEXT1 und TEXT2 verschieden

* Numerischer Vergleich (nur ganze Zahlen, kein Text oder leer erlaubt):

  NUM1 -eq NUM2      # Zahl NUM1 gleich NUM2 [equal]
  NUM1 -ne NUM2      # Zahl NUM1 NICHT gleich NUM2 [not equal]
  NUM1 -le NUM2      # Zahl NUM1 kleiner gleich NUM2 [less equal]
  NUM1 -lt NUM2      # Zahl NUM1 kleiner NUM2 [less than]
  NUM1 -ge NUM2      # Zahl NUM1 größer gleich NUM2 [greater equal]
  NUM1 -gt NUM2      # Zahl NUM1 größer NUM2 [greater than]

* Logische Verknüpfung (Vorrang von oben nach unten):

  \( ... \)          # Klammerung (quotiert wg. Shell!)
  \! EXPR            # Negation von EXPR [not]
  EXPR1 -a EXPR2     # EXPR1 und EXPR2 [and]
  EXPR1 -o EXPR2     # EXPR1 oder EXPR2 [or]

2.1) Nur in der Bash vorhandene Bedingungen   (Toc)

* Dateiexistenz-Vergleich:

  -a FILE            # Datei FILE existiert (analog "-e") [available]

* Dateityp-Vergleich (gleichzeitig Existenz-Test):

  -h FILE            # Datei FILE ein symbolischer Link (analog "-L")

* Datei-Besitzer/Besitzergruppe-Vergleich:

  -G FILE            # Datei FILE gehört effektiver Group-ID [Group]
  -O FILE            # Datei FILE gehört effektiver User-ID [Owner]

* Dateialter-Vergleich bzgl. Inode-Vergleich:

  -N FILE1           # Datei FILE1 seit letztem Lesen verändert [New]
  FILE1 -nt FILE2    # Datei FILE1 neuer als FILE2 [newer than]
                     # (oder FILE1 existiert und FILE2 existiert NICHT)
  FILE1 -ot FILE2    # Datei FILE1 älter als FILE2 [older than]
                     # (oder FILE2 existiert und FILE1 existiert NICHT)
  FILE1 -ef FILE2    # Dateien haben gleiche Device + Inode-Nummer [equal file]

* Text-Vergleich:

  "TEXT1" == "TEXT2" # TEXT1 und TEXT2 gleich (analog "=")
  "TEXT1" \< "TEXT2" # TEXT1 alphabetisch kleiner als TEXT2 (quotiert wg. Shell]
  "TEXT1" \> "TEXT2" # TEXT1 alphabetisch größer als TEXT2 (quotiert wg. Shell]

* Shell-Variable testen:

  -v VAR             # Variable VAR gesetzt/hat einen Wert [variable]
  \! -v VAR          # Variable VAR NICHT gesetzt/undefiniert [not variable]
  -R VAR             # Variable VAR gesetzt und ist eine Namensreferenz [reference]

* Shell-Option testen:

  -o OPT             # Shell-Option OPT gesetzt [option]
  \! -o OPT          # Shell-Option OPT NICHT gesetzt [not option]

2.2) Nur in [[...]] vorhandene Bedingungen   (Toc)

* Vergleich mit Regulärem Ausdruck:

  "TEXT" =~ REGEX    # Regulärer Ausdruck passt zu Text (KEIN "..." oder /.../ um REGEX!)



HINWEIS: Folgende Unterschiede zu "test" bzw. "[...]" gibt es:

* Innendrin findet keine Wort-Zerlegung und Pfadnamen-Expansion statt, aber
  Tilde-Expansion, Parameter + Variablen-Substitution, Arithmetische Auswertung,
  Kommando-Substitution, Prozess-Substitution, Entfernung der Quotierung
  (d.h. automatisch quotiert in "...").

* "<" und ">" sortiert LEXIKOGRAFISCH gemäß locale-Einstellung
  (statt gemäß ASCII-Reihenfolge).

* Shell-Option "nocasematch" schaltet Berücksichtigung von GROSS/kleinschreibung ab.

* Operator "=" und "==" machen Dateinamen-Matching (Globbing)
  als ob die Shell-Option "extglob" aktiv wäre.

* Innendrin Quotierung der Shell-Sonderzeichen * < > ! ( ) ... nicht nötig.

* Innendrin statt "-a" und "-o" auch "&&" und "||" nutzbar.