#!/bin/bash
#!/bin/bash -u
#-------------------------------------------------------------------------------
# bashcode.sh                               (C) 2004-2011 T.Birnthaler OSTC GmbH
# Die Anweisungen der "bash/ksh/sh" ausprobieren.
# $Id: bashcode.sh,v 1.5 2011/12/09 14:27:48 tsbirn Exp tsbirn $
#-------------------------------------------------------------------------------
# Die Shee-Bang-Zeile "#!/bin/bash -u" IMMER in 1.Zeile/1.Spalte angeben
# (-u=undefined => Zugriff auf nicht definierte Variable loest Fehler aus).
#-------------------------------------------------------------------------------
# Aufgrund des hohen Alters der Shell und ihrer Verwendung als interaktiver
# Kommandointerpreter sind einige ihrer Syntax-Eigenschaften widerspruechlich.
# Dies betrifft vor allem LEERZEICHEN, die an manchen Stellen vorhanden sein
# MueSSEN, an anderen Stellen aber NICHT erlaubt sind. Dies ist verwirrend, da
# in den ueblichen Programmiersprachen solche Regeln (meist) nicht existieren.
#-------------------------------------------------------------------------------
# TODO:
# * Rechenoperationen nochmal ueberpruefen
# * Koprozesse
# DONE:
# * Umlaute äöüÄÖÜß-> aeoeueAeOeUess austauschen (portabel)
# * help -> Liste der Shell-Schluesselworte
# * help CMD -> Kurzerklaerung Shell-Kommando
# * Regulaere Ausdruecke mit [[ ... =~ ... ]]
#-------------------------------------------------------------------------------

# Variable status wegen "-u" definieren
status=

#-------------------------------------------------------------------------------
# Dokumentation
#-------------------------------------------------------------------------------
help                                      # Liste der Bash-Befehle
echo
help shopt                                # Kurzanleitung zu Bash-Befehl "shopt"

#-------------------------------------------------------------------------------
# Shell-Variablen initialisieren (KEIN Leerzeichen um "=" erlaubt!)
#-------------------------------------------------------------------------------
echo
  TXT=                                    # Leerer Wert
  TXT=""                                  # Leerer Wert
  TXT=''                                  # Leerer Wert
 TEXT=EinWort                             # KEIN Quotierung noetig
TEXT2="Mehr als ein Wort"                 # Quotierung notwendig (Quotierung)!
 ZAHL="12345"                             # Zahl (wird als Text repraesentiert!)
 PATH=/bin:/usr/bin:/sbin:/usr/sbin       # Sinnvoll: Standard-Suchpfad
 PATH="/bin:/usr/bin:/sbin:/usr/sbin"     # Analog (Quotierung unnoetig)

#-------------------------------------------------------------------------------
# Umgebungs-Variablen erzeugen und initialisieren
#-------------------------------------------------------------------------------
export GLOBAL1                            # Variante A: ok
GLOBAL1="Wert 1"                          # (erst export, dann Zuweisung)

GLOBAL2="Wert 2"                          # Variante B: ok
export GLOBAL2                            # (erst Zuweisung, dann export)

export GLOBAL3="Wert 3"                   # Variante C: ok (nur bash + ksh)
                                          # (export und Zuweisung gleichzeitig)
#-------------------------------------------------------------------------------
# Shell/Umgebungs-Variable loeschen
#-------------------------------------------------------------------------------
unset TXT
unset GLOBAL1

#-------------------------------------------------------------------------------
# Signale abfangen (ALLE Signale ausser SIGKILL/9 sind abfangbar!)
# Liste der Signale mit "kill -l" bzw. "man 7 signal"
#-------------------------------------------------------------------------------
trap 'echo "Signal angekommen"' 1 2 3 15  # Die Signale 1=HUP, 2=INT=Strg-C
                                          # 3=QUIT und 15=TERM=kill abfangen
trap '' 1 2 3 15                          # Die 4 Signale ignorieren
trap 1 2 3 15                             # Standardbehandlung der 4 Signale
trap                                      # Liste der Kommandos pro Signal

#-------------------------------------------------------------------------------
# Variable einlesen und ausgeben
#-------------------------------------------------------------------------------
echo
echo -n "Bitte Text eingeben: "           # -n=KEIN Zeilenvorschub nach "echo"
                                          # (Leerzeichen am Zl.ende sinnvoll)
read EINGABE                              # Benutzereingabe lesen (bis RETURN)
echo "Eingegeben wurde: $EINGABE"

echo
read -p "Bitte Text eingeben: " EINGABE   # Analog (-p=prompt)
echo "Eingegeben wurde: $EINGABE"

WAHL=x
echo
read -n 1 -t 2 -p "Bitte Buchstabe a, b oder c eingeben: " WAHL    # -n=number of chars, -t=timeout
echo
echo "Eingegeben wurde: $WAHL"            # 1 Zeichen lesen, max. 5 Sek. warten

#-------------------------------------------------------------------------------
# Kommandosubstitution = Ausgabe eines externen Befehl in Shell weiterverwenden)
# (per `...` ueberall, per $(...) nur in "bash" erlaubt)
#-------------------------------------------------------------------------------
echo
AUSGABE=`date`                            # Datum+Zeit in Variable speichern
echo "AUSGABE=$AUSGABE"
AUSGABE=$(date)                           # Datum+Zeit in Variable speichern
echo "AUSGABE=$AUSGABE"

#-------------------------------------------------------------------------------
# Bedingungen ueberpruefen ("test" liefert fuer "wahr/falsch" den Exit-Code "0/1",
#                         der in if, while und until zur Entscheidung dient)
# IMMER Gaensefuesschen bei Variablenzugriff (wg. leerer Var. => Syntaxfehler!)
# IMMER Leerzeichen um Operatoren (z.B. -r) und Operanden (z.B. /tmp) angeben!
#-------------------------------------------------------------------------------
echo
# (A) Zugriffsrechte testen
test -r /etc/passwd                       # Datei lesbar (-r=readable)
test -w /tmp                              # Datei schreibbar (-w=writable)
[ -w /tmp ]                               # Analog (besser lesbar!)
test -x /usr/bin/bash                     # Datei ausfuehrbar (-x=executable)
test -u /usr/bin                          # Datei hat Set-User-ID gesetzt
test -g /usr/bin                          # Datei hat Set-Group-ID gesetzt
test -k /usr/bin                          # Datei hat Sticky-Bit gesetzt

# (B) Datei-Besitzer und Besitzer-Gruppe testen
test -O /usr/lib/include                  # Datei von akt. Besitzer besessen
test -G /usr/lib/include                  # Datei von akt. Besitzer-Gruppe besessen

# (C) Datei-Existenz und -Groesse testen
test -a /usr/lib/include                  # Datei existiert (-a=available)
test -e /usr/lib/include                  # Datei existiert (-e=existent)
test -s /usr/bin                          # Datei ist NICHT leer (-s=size)
test /etc -ef /var                        # Datei1+Datei2 Hardlinks von id. Datei (equal file)

# (D) Datei-Alter testen
test -N /usr/bin/                         # Datei seit letztem Lesen veraendert (New)
test /etc -nt /var                        # Datei1 neuer als Datei2 (newer than)
test /etc -ot /var                        # Datei1 aelter als Datei2 (older than)

# (E) Datei-Typen testen
# IMMER -L=Link VOR allen anderen Testen!
test -L /usr/bin                          # Name ... Symbol. Link (-L=symlink)
test -h /usr/bin                          # Name ... Symbol. Link (-h=symlink)
test -f /etc/shadow                       # Name bezeichnet eine Datei (-f=file)
test -d /usr/bin                          # Name ... Verzeichnis (-d=directory)
test -c /usr/bin                          # Name ... Zeichengeraet (-c=character)
test -b /usr/bin                          # Name ... Blockgeraet (-b=block)
test -S /usr/bin                          # Name ... Socket (-S=socket)
test -p /usr/bin                          # Name ... Named Pipe (-p=pipe)
test -t /usr/bin                          # Name ... Terminal (-t=tty)

# (F) Strings vergleichen (Variablenzugriff IMMER in Gaensefuesschen setzen!)
test -n "$TEXT"                           # Variable ist NICHT leer (-n=notzero)
test -z "$TEXT"                           # Variable ist leer (-z=zero)
test "$TEXT" = "ja"                       # Variable gleich Text
test "$TEXT" != "ja"                      # Variable ungleich Text
test "$TEXT" \< "ja"                      # Variable alphabetisch kleiner Text
test "$TEXT" \> "ja"                      # Variable alphabetisch groesser Text

# (G) Zahlen vergleichen (NICHT "=" und "!=" = Textvergleich verwenden!)
ZAHL=10                                   # Var. NICHT init. => Syntaxfehler!
test "$ZAHL" -eq 10                       # Variable gleich 10 (-eq=equal)
test "$ZAHL" -ne 10                       # Var. ungleich 10 (-ne=not equal)
test "$ZAHL" -gt 10                       # Var. groesser als 10 (-gt=greater than)
test "$ZAHL" -ge 10                       # groesser/gl. 10 (-ge=greater or equal)
test "$ZAHL" -lt 10                       # Var. kleiner 10 (-lt=less than)
test "$ZAHL" -le 10                       # kleiner/gleich 10 (-le=less or equal)

#-------------------------------------------------------------------------------
# (H) Regulaere Ausdruecke vergleichen
#   * Nur per [[...]], nicht per [...] und test moeglich
#   "..." um regulaeren Ausdruck -> Stringvergleich (Metazeichen = normale Zeichen)
#   " " mit \ schuetzen, nicht mit "..."
#   !~ gibt es nicht (passt nicht zu)
#-------------------------------------------------------------------------------
shopt -s nocasematch                      # GROSS/kleinschreibung beachten (set)
[[ "Hallo" =~ a.*o ]]                     # Passt zu
[[ "Hallo" =~ A.*o ]]                     # Passt zu
[[ ! "Hallo" =~ a.*o ]]                   # Passt NICHT zu
[[ ! "Hallo" =~ A.*o ]]                   # Passt NICHT zu
shopt -u nocasematch                      # GROSS/kleinschreibung ignorieren (unset)
[[ "Hallo" =~ a.*o ]]                     # Passt zu
[[ "Hallo" =~ A.*o ]]                     # Passt zu
[[ ! "Hallo" =~ a.*o ]]                   # Passt NICHT zu
[[ ! "Hallo" =~ A.*o ]]                   # Passt NICHT zu

# (I) Logische Bedingungen und Verknuepfungen
test -o nocasematch                       # Shell-Option aktiviert (on)
test ! -o nocasematch                     # Shell-Option deaktiviert (not on)
test 1 -o 2                               # Oder-Verknuepfung (or)
test 1 -a 2                               # Und-Verknuepfung (and)
test ! 1                                  # Nicht-Verknuepfung (not)

#-------------------------------------------------------------------------------
# Folgende Schreibweise fuer Bedingungs-Test ist auch moeglich (besser lesbar):
# Schluesselwort "test" weglassen, statt dessen die eckige Klammern [ ... ] um
# die Bedingung setzen (UNBEDINGT Leerzeichen um "[", "]" und "-le" setzen)!
# NIE test und [...] gleichzeitig verwenden!
#-------------------------------------------------------------------------------
[ -w /tmp ]                               # Datei schreibbar (w=writable)
[ "$ZAHL" -le 10 ]                        # kleiner/gleich 10 (le=less or equal)

#-------------------------------------------------------------------------------
# Rechnen (mit "expr" in jeder Shell einheitlich, ohne "expr" nur in bash + ksh)
#-------------------------------------------------------------------------------
ZAHL=0                                    # Klassisch per expr (Shell kann nicht)
ZAHL=$(expr $ZAHL + 1 \* 9 % 5 - 4 / 2)   # 0 + 9 % 5 - 2 -> 4 - 2 -> 2
echo "ZAHL=$ZAHL"
#ZAHL=$(expr ZAHL + 1 \* 9 % 5 - 4 / 2)   # Variable OHNE "$" NICHT erlaubt!
#echo "ZAHL=$ZAHL"

START=11
declare -i ZAHL                           # Variable vom Typ Integer
ZAHL=$START+11                            # KEINE Leerzeichen erlaubt!
echo "ZAHL=$START+11 -> $ZAHL"
ZAHL=START+22                             # Variable OHNE "$" erlaubt!
echo "ZAHL=$START+22 -> $ZAHL"

let ZAHL=$START+333                       # KEINE Leerzeichen erlaubt!
echo "let ZAHL=$START+333 -> $ZAHL"
let ZAHL=START+444
echo "let ZAHL=$START+444 -> $ZAHL"       # Variable OHNE "$" erlaubt!

let ZAHL=" $START + 555 "                 # Leerzeichen erlaubt!
echo "let ZAHL=' $START + 555 ' -> $ZAHL"
let ZAHL=" START + 666 "                  # Variable OHNE "$" erlaubt!
echo "let ZAHL=' $START + 666 ' -> $ZAHL"

ZAHL=$(( $START + 777 ))                  # Leerzeichen erlaubt!
echo "ZAHL=\$(( $START + 777 )) -> $ZAHL"
ZAHL=$(( START + 888 ))                   # Variable OHNE "$" erlaubt!
echo "ZAHL=\$(( $START + 888 )) -> $ZAHL"

ZAHL=$[ $START + 999 ]                    # Leerzeichen erlaubt, veraltet!
echo "ZAHL=\$[ $START + 999 ] -> $ZAHL"
ZAHL=$[ START + 11 ]                      # Variable OHNE "$" erlaubt!
echo "ZAHL=\$[ $START + 11 ] -> $ZAHL"

#-------------------------------------------------------------------------------
# Rechenoperatoren bei ((...))
#-------------------------------------------------------------------------------
echo
set ZAHL  = 123
set START = 456

ERG=$(( $ZAHL + $START ))                 # + = Addition
echo "$ZAHL + $START -> $ERG"

echo -n "++$ERG -> "
((++ERG))                                 # ++ = Increment
echo "$ERG"

ERG=$(( $ZAHL - $START ))                 # - = Subtraktion
echo "$ZAHL - $START -> $ERG"

echo -n "--$ERG -> "
((--ERG))                                 # -- = Decrement
echo "$ERG"

ERG=$(( $ZAHL * $START ))                 # * = Multiplikation
echo "$ZAHL * $START -> $ERG"

ERG=$(( $ZAHL ** $START ))                # ** = Potenzierung
echo "$ZAHL ** $START -> $ERG"

ERG=$(( $ZAHL / $START ))                 # / = Division
echo "$ZAHL / $START -> $ERG"

ERG=$(( $ZAHL % $START ))                 # % = Modulo (Divisionsrest)
echo "$ZAHL % $START -> $ERG"

ERG=$(( $ZAHL || $START ))                # || = logisch OR
echo "$ZAHL || $START -> $ERG"

ERG=$(( $ZAHL && $START ))                # && = logisch AND
echo "$ZAHL && $START -> $ERG"

ERG=$(( ! $ZAHL ))                        # ! = logisch NOT
echo "! $ZAHL -> $ERG"

ERG=$(( $ZAHL | $START ))                 # | = bitweise OR
echo "$ZAHL | $START -> $ERG"

ERG=$(( $ZAHL & $START ))                 # & = bitweise AND
echo "$ZAHL & $START -> $ERG"

ERG=$(( $ZAHL ^ $START ))                 # ^ = bitweise XOR
echo "$ZAHL ^ $START -> $ERG"

ERG=$(( ~ $ZAHL ))                        # ~ = bitweise NOT
echo "~ $ZAHL -> $ERG"

ERG=$(( $ZAHL << 2 ))                     # << = bitweise left SHIFT
echo "$ZAHL << 2 -> $ERG"

ERG=$(( $ZAHL >> 2 ))                     # >> = bitweise right SHIFT
echo "$ZAHL >> 2 -> $ERG"

#-------------------------------------------------------------------------------
# if-elif-else-Verzweigung
#-------------------------------------------------------------------------------
echo
ZAHL=10                                   # Leerz. um "=" => Syntaxfehler!
if [ $ZAHL -gt 2 ]                        # Leerzeichen um "[", "]" und "-gt"!
then                                      # "then" muss auf neuer Zeile stehen!
	echo "if: $ZAHL ist groesser als 2"
elif [ $ZAHL -lt 2 ]                      # NICHT "else if" "elseif" "elsif"!
then                                      # "then" muss auf neuer Zeile stehen!
	echo "if: $ZAHL ist kleiner als 2"
else
	echo "if: $ZAHL ist gleich 2"
fi                                        # "fi" nicht vergessen (neue Zeile)!

#-------------------------------------------------------------------------------
# for-Schleife (Wort-Liste abarbeiten)
# (ACHTUNG: Hinter line-continuation "\" darf KEIN Zeichen mehr folgen)
#-------------------------------------------------------------------------------
echo
# for ELEM in *.txt *.doc *.lst
for ELEM in abc defghi jklmnopqr stu \
            vw xy z                       # ELEM enthaelt Werte aus Wort-Liste
do                                        # "do" muss auf neuer Zeile stehen!
	echo "for: ELEM=$ELEM"
done                                      # "done" nicht vergessen (neue Zeile)!

#-------------------------------------------------------------------------------
# for-Schleife (ALLE Aufruf-Argumente "$*" bzw. "$@" abarbeiten)
#-------------------------------------------------------------------------------
echo
for ARG                                   # ELEM enthaelt nacheinand. Shell-Arg.
do                                        # "do" muss auf neuer Zeile stehen!
	echo "for: ARG=$ARG"
done                                      # "done" nicht vergessen (neue Zeile)!

#-------------------------------------------------------------------------------
# while-Schleife (Schleife wird durchlaufen, SOLANGE BEDINGUNG erfuellt ist)
#-------------------------------------------------------------------------------
echo
ZAEHLER=3
while [ $ZAEHLER -gt 0 ]
do                                        # "do" muss auf neuer Zeile stehen!
	echo "while: ZAEHLER=$ZAEHLER"
	ZAEHLER=$(expr $ZAEHLER - 1)          # Kommando-Subst (Leerz. um "-" noetig)
done                                      # "done" nicht vergessen (neue Zeile)!

#-------------------------------------------------------------------------------
# until-Schleife (Schleife wird solange durchlaufen, BIS BEDINGUNG erfuellt ist)
#-------------------------------------------------------------------------------
echo
until [ $ZAEHLER -eq 3 ]
do                                        # "do" muss auf neuer Zeile stehen!
	echo "until: ZAEHLER=$ZAEHLER"
	ZAEHLER=$(expr $ZAEHLER + 1)          # Kommando-Subst (Leerz. um "+" noetig)
done                                      # "done" nicht vergessen (neue Zeile)!

#-------------------------------------------------------------------------------
# repeat-Schleife (feste Anzahl Wiederholungen)
#-------------------------------------------------------------------------------
# GIBT ES NICHT!

#-------------------------------------------------------------------------------
# Schleifendurchlauf oder gesamte Schleife vorzeitig abbrechen
# (mehrere Anweisungen mit ";" statt mit Newline zu trennen ist erlaubt!)
#-------------------------------------------------------------------------------
echo
for I in 1 2 3 4 5 6 7 8 9 10
do
	if [ "$I" -eq 3 ]; then continue; fi  # Schleife bei "3" auf naechsten Wert
	if [ "$I" -eq 7 ]; then break; fi     # Schleife bei "7" abbrechen
	echo "I=$I"
done

#-------------------------------------------------------------------------------
# Zaehlschleife (eher ungewoehnlich in der Shell)
#-------------------------------------------------------------------------------
echo
for N in 1 2 3 4 5 6 7 8 9 10             # Aufsteigend
do
	echo "$N. Durchlauf"
done
echo "Endwert: N=$N"

echo
for N in 10 9 8 7 6 5 4 3 2 1             # Absteigend
do
	echo "$N. Durchlauf"
done
echo "Endwert: N=$N"

echo
for N in $(seq 10)                        # Aufsteigend 1 2 ... 10
do                                        # (auch "seq 1 10" oder "seq 1 1 10")
	echo "$N. Durchlauf"
done
echo "Endwert: N=$N"

echo
for (( N = 1; N <= 10; ++N ))             # Analog for-Schleife in C (Zaehler)
do                                        # (nur bash!)
	echo "$N. Durchlauf"
done
echo "Endwert: N=$N"

echo
for (( N = 10; N > 0; --N ))              # Absteigend
do                                        # (nur bash!)
	echo "$N. Durchlauf"
done
echo "Endwert: N=$N"

#-------------------------------------------------------------------------------
# Auswahl aus Liste
#-------------------------------------------------------------------------------
echo
echo "Bitte per Nummer auswaehlen:"
select WAHL in "deutsch" "englisch" "franzoesisch"
do
	if [ "$WAHL" ]
	then
		echo "Auswahl: $WAHL"
		break;
	fi
done
echo "Ausgewaehlt wurde: $WAHL"

#-------------------------------------------------------------------------------
# switch-case-Mehrfachverzweigung (Text-Vergleich mit Shell-Metazeichen)
# In Reihenfolge der Muster verglichen, Anweisungen nach 1. zutreffenden Muster
# werden ausgefuehrt, else-Zweig per "*)" als letztem Muster realisieren.
#-------------------------------------------------------------------------------
echo
TEXT="Moses"                              # Zum Testen Zeilen vertauschen
TEXT="Mulut"                              # Zum Testen Zeilen vertauschen
TEXT="Anton"                              # Zum Testen Zeilen vertauschen
TEXT="Babel"                              # Zum Testen Zeilen vertauschen
TEXT=
case "$TEXT" in                           # "in" nicht vergessen!
	A*) echo "case: Anton gefunden" ;;    # Abschluss ";;" nicht vergessen!
	M*) echo "case: Moses oder Mulut gefunden"
		;;                                # Abschluss ";;" nicht vergessen!
	*)  echo "case: Babel gefunden" ;;    # else-Zweig
esac                                      # "esac" nicht vergessen (neue Zeile)!

#-------------------------------------------------------------------------------
# Label und "goto" IST NICHT MoeGLICH!
# (toll, und das bei einer ueber 30 Jahre alten Programmiersprache!)
#-------------------------------------------------------------------------------

#-------------------------------------------------------------------------------
# Funktions-Definition (VOR Funktions-Aufruf notwendig!)
# TIPP: Geschweifte Klammern auf extra Zeile setzen (sonst ";" notwendig!)
#-------------------------------------------------------------------------------
func1()                                   # Leere "()" notwendig
{                                         # Extra Zeile!
	echo "Hier ist func1()"               # Einruecken sinnvoll
}                                         # Extra Zeile!

#-------------------------------------------------------------------------------
# Funktions-Aufruf OHNE uebergabe von Argumenten (NACH Funktions-Definition!)
# Nur Name der Funktion ist anzugeben, keine Klammern
#-------------------------------------------------------------------------------
echo
echo "Aufruf von func1 ohne Argumente"
func1

#-------------------------------------------------------------------------------
# Funktions-Definition mit Nutzung von Positions-Parametern $1 $2 $3 ...
# (die Zeichen "<" und ">" dienen nur zur Hervorhebung!)
#-------------------------------------------------------------------------------
function func2()                          # "function" optional angebbar
{                                         # Extra Zeile!
	echo "Hier ist func2()"               # Einruecken sinnvoll
	echo "Alle Funktions-Parameter: <$*>" # Variante A
	echo "Alle Funktions-Parameter: <$@>" # Variante B
	echo "Anzahl Funktions-Parameter: <$#>"
	echo "1. Funktions-Parameter: <$1>"
	echo "2. Funktions-Parameter: <$2>"
	echo "3. Funktions-Parameter: <$3>"
	echo "4. Funktions-Parameter: <$4>"
	echo "5. Funktions-Parameter: <$5>"
	echo "6. Funktions-Parameter: <$6>"
	echo "7. Funktions-Parameter: <$7>"
	echo "8. Funktions-Parameter: <$8>"
	echo "9. Funktions-Parameter: <$9>"
}                                         # Extra Zeile!

#-------------------------------------------------------------------------------
# Funktions-Aufruf MIT uebergabe von Argumenten
#-------------------------------------------------------------------------------
echo
echo "Aufruf von func2 mit Argumenten"
func2 Dies "" ist "ein Test" "   " 1 2 3 4 5 6 7 8 9 10

#-------------------------------------------------------------------------------
# Je nachdem, ob Skript-Parameter angegeben wurden oder nicht, etwas anderes tun
#-------------------------------------------------------------------------------
echo
if [ $# -eq 0 ]
then
	echo "KEINE Skript-Parameter angegeben, setze selber welche!"
	set -- Im Skript gesetzte Parameter da keine von aussen gesetzt.
else
	echo "Folgende Skript-Parameter angegeben: $*"
fi

#-------------------------------------------------------------------------------
# Skript-Aufruf-Parameter verarbeiten (SKRIPT PARAM1 PARAM2 ...)
#-------------------------------------------------------------------------------
echo "Skript-Name:                   $0"  # Im Skript verwendbar!
echo "Alle Skript-Parameter:         $*"  # Variante A
echo "Alle Skript-Parameter:         $@"  # Variante B
echo "Anzahl Skript-Parameter:       $#"
echo "1. Skript-Parameter (1. Wort): $1"
echo "2. Skript-Parameter (2. Wort): $2"
echo "3. Skript-Parameter (3. Wort): $3"
echo "4. Skript-Parameter (4. Wort): $4"
echo "5. Skript-Parameter (5. Wort): $5"
echo "6. Skript-Parameter (6. Wort): $6"
echo "7. Skript-Parameter (7. Wort): $7"
echo "8. Skript-Parameter (8. Wort): $8"
echo "9. Skript-Parameter (9. Wort): $9"

shift 3
echo "Alle Skript-Parameter nach shift 3: $@"   # Variante B

#-------------------------------------------------------------------------------
# Weitere spezielle Skript-Variablen
#-------------------------------------------------------------------------------
echo
echo "Letzter Exit-Status:                $?"   # <= Nur 1x lesbar, dann
echo "Letzter Exit-Status:           $status"   # ist der Exit-Status
echo "Prozessnummer der Skript-Shell:     $$"   # des naechsten Kommandos
sleep 10 &                                      # darin zu finden.
echo "Nummer letzter Hintergrund-Prozess: $!"
echo "Beim Aufruf angeg. Shell-Optionen:  $-"

#-------------------------------------------------------------------------------
# Bedingte Variablen
#-------------------------------------------------------------------------------
echo
# Variablen koennen 3 verschiedene Zustaende haben
# (Schalter -u=undefined bricht Skript bei Zugriff auf undefinierte Variable ab)
unset VARu           # 1) undefiniert (bei Zugriff als "leer" behandelt)
      VARl=""        # 2) leer (definiert)
      VARg=Wert      # 3) gefuellt (definiert)
echo "VARu=$VARu  VARl=$VARl  VARg=$VARg"

echo "Default falls undefiniert: "
echo "VARu=${VARu-Dflt} VARl=${VARl-Dflt} VARg=${VARg-Dflt}"
echo "VARu=$VARu  VARl=$VARl  VARg=$VARg"

echo "Default + setzen falls undefiniert: "
echo "VARu=${VARu=Dflt} VARl=${VARl=Dflt} VARg=${VARg=Dflt}"
echo "VARu=$VARu  VARl=$VARl  VARg=$VARg"

unset VARu                                # undefiniert
      VARl=""                             # leer (definiert)
      VARg=Wert                           # gefuellt (definiert)

echo "Default falls definiert: "
echo "VARu=${VARu+Dflt} VARl=${VARl+Dflt} VARg=${VARg+Dflt}"
echo "VARu=$VARu  VARl=$VARl  VARg=$VARg"

echo "Default falls undefiniert oder leer: "
echo "VARu=${VARu:-Dflt} VARl=${VARl:-Dflt} VARg=${VARg:-Dflt}"
echo "VARu=$VARu  VARl=$VARl  VARg=$VARg"

echo "Default + setzen falls undefiniert oder leer: "
echo "VARu=${VARu:=Dflt} VARl=${VARl:=Dflt} VARg=${VARg:=Dflt}"
echo "VARu=$VARu  VARl=$VARl  VARg=$VARg"

unset VARu                                # undefiniert
      VARl=""                             # leer (definiert)
      VARg=Wert                           # gefuellt (definiert)

echo "Default falls definiert und nicht leer: "
echo "VARu=${VARu:+Dflt} VARl=${VARl:+Dflt} VARg=${VARg:+Dflt}"
echo "VARu=$VARu  VARl=$VARl  VARg=$VARg"

#-------------------------------------------------------------------------------
# Verzweigung abhaengig vom Skript-Namen
# (Kommandosubstitution per `...` ueberall, per $(...) nur in "bash" erlaubt)
#-------------------------------------------------------------------------------
echo
NAME=`basename $0 .sh`                    # Pfad + Endung ".sh" entfernen
NAME=$(basename $0 .sh)                   # Pfad + Endung ".sh" entfernen

if [ $0 = "bashcode" ]
then
	echo "Skript heisst 'bashcode'"
else
	echo "Name des Skriptes lautet '$NAME'"
fi

echo "Pfad des Skriptes: `dirname $0`"    # Pfadanteil ausgeben
echo "Pfad des Skriptes: $(dirname $0)"   # Pfadanteil ausgeben

#-------------------------------------------------------------------------------
# Array-Variablen ausprobieren.
# * Indices sind:
#   + numerisch von 0 bis unendlich oder
#   + beliebiger Text (assoziativ, Hash) -> declare -A notwendig
# * Arrays sind 1-dimensional
# * Ihre Groesse ist beliebig
# * numerische Indices muessen nicht aufeinanderfolgen
#-------------------------------------------------------------------------------
echo
declare -a NUM                            # num. Array deklarieren (nicht unbed. noetig)

NUM[1]=123                                # Ein Element fuellen
NUM[2]="xyz"                              # Ein Element fuellen
NUM[3]=789                                # Ein Element fuellen
                                          # Zugriff mit {...} notwendig
echo "NUM[1]=${NUM[1]}"                   # Element ausgeben, {...} notwendig
echo "NUM[2]=${NUM[2]}"                   # Element ausgeben, {...} notwendig
echo "NUM[3]=${NUM[3]}"                   # Element ausgeben, {...} notwendig
echo "ANZa=${#NUM[*]} NUM=${NUM[*]}"      # Arraylaenge + -Inhalt ausgeben

NUM[1]+=111                               # Stringverkettung
NUM[2]+="abc"                             # Stringverkettung
NUM[3]+="def"                             # Stringverkettung
echo "NUM[1]=${NUM[1]}"                   # Element ausgeben, {...} notwendig
echo "NUM[2]=${NUM[2]}"                   # Element ausgeben, {...} notwendig
echo "NUM[3]=${NUM[3]}"                   # Element ausgeben, {...} notwendig
echo "ANZb=${#NUM[*]} NUM=${NUM[*]}"      # Arraylaenge + -Inhalt ausgeben

unset NUM                                 # Array loeschen (Datentyp)
declare -i NUM                            # Integer-Array deklarieren (kein String) (kein String)

NUM[1]+=111                               # Numerisch addieren
NUM[2]+="abc"                             # Numerisch addieren
NUM[3]+=111                               # Numerisch addieren
echo "NUM[1]=${NUM[1]}"                   # Element ausgeben, {...} notwendig
echo "NUM[2]=${NUM[2]}"                   # Element ausgeben, {...} notwendig
echo "NUM[3]=${NUM[3]}"                   # Element ausgeben, {...} notwendig
echo "ANZc=${#NUM[*]} NUM=${NUM[*]}"      # Arraylaenge + -Inhalt ausgeben

unset NUM                                 # Array loeschen (Datentyp)
NUM=(v1 v2 v3 v4 v5 v6)                   # Array = Elemente 0..5 fuellen
echo "NUM[0]=${NUM[0]}"                   # Element ausgeben, {...} notwendig
echo "NUM[0]=$NUM"                        # Identisch zu ${NUM[0]}
echo "NUM[1]=${NUM[1]}"                   # Element ausgeben, {...} notwendig
echo "NUM[2]=${NUM[2]}"                   # Element ausgeben, {...} notwendig
echo "NUM[3]=${NUM[3]}"                   # Element ausgeben, {...} notwendig
echo "NUM[4]=${NUM[4]}"                   # Element ausgeben, {...} notwendig
echo "NUM[5]=${NUM[5]}"                   # Element ausgeben, {...} notwendig
echo "NUM[6]=${NUM[6]}"                   # Leeres Element ausgeben, {...} notwendig
echo "ANZd=${#NUM[@]} NUM=${NUM[*]}"      # Arraylaenge + -Inhalt ausgeben

NUM=([0]=val1 [3]=val2 [9]=val3)
echo "ANZe=${#NUM[*]} NUM=${NUM[@]}"      # Arraylaenge + -Inhalt ausgeben
NUM=([0]=val1 val2 val3 [3]=val4 val5 val6 [9]=val7)
echo "ANZf=${#NUM[@]} NUM=${NUM[@]}"      # Arraylaenge + -Inhalt ausgeben

unset NUM[1]                              # Zweites Element loeschen
echo "ANZg=${#NUM[*]} NUM=${NUM[*]}"      # Arraylaenge + -Inhalt ausgeben

unset NUM                                 # Array loeschen (Datentyp)
echo "ANZh=${#NUM[@]} NUM=${NUM[@]}"      # Arraylaenge + -Inhalt ausgeben

for N in 1 2 3 4 5 6 7 8 9 10             # 10 Arrayelemente fuellen
do
	NUM[$N]="`expr $N \* $N`"
done

for N in 1 2 3 4 5 6 7 8 9 10             # 10 Arrayelemente ausgeben
do
	echo "NUM[$N] = ${NUM[$N]}"
done
echo "ANZi=${#NUM[*]} NUM=${NUM[@]}"      # Arraylaenge + -Inhalt ausgeben

echo -en "\nBitte mehrere Texte eingeben: "   # Textstuecke in Array einlesen
read -a INP <(echo "abc def ghi")         # Eingabe in Array einlesen
for N in $(seq 0 ${#INP[*]})              # Gelesene Elemente + 1 ausgeben
do
	echo "INP[$N]=${INP[$N]}"
done
echo "ANZj=${#INP[@]} INP=${INP[*]}"      # Arraylaenge + -Inhalt ausgeben

NUM[0]="null"                             # Ok
#NUM[-1]="minus1"                         # nicht erlaubt
echo "NUM[0]=${NUM[0]}"
echo "ANZk=${#NUM[@]} NUM=${NUM[@]}"      # Arraylaenge + -Inhalt ausgeben

# Hohe Indices benutzen
for N in 0 1 2 4 8 16 32 64 128 256 512 \
         1024 2048 4096 8192 16384 32768 65536
do
	NUM[$N]="`expr $N \* $N`"
done
for N in 0 1 2 4 8 16 32 64 128 256 512 \
         1024 2048 4096 8192 16384 32768 65536
do
	echo "NUM[$N]  = ${NUM[$N]}"
done
echo "ANZl=${#NUM[*]} NUM=${NUM[@]}"      # Arraylaenge + -Inhalt ausgeben

#-------------------------------------------------------------------------------
# Assoziatives Array ausprobieren
#-------------------------------------------------------------------------------
echo
declare -A ASSOC                              # assoz. Array deklarieren (noetig)

ASSOC[a]=123                                  # Ein Element fuellen
ASSOC[bc]="xyz"                               # Ein Element fuellen
ASSOC[def]=789                                # Ein Element fuellen
echo "ASSOC[a]=${ASSOC[a]}"                   # Element ausgeben, {...} notwendig
echo "ASSOC[bc]=${ASSOC[bc]}"                 # Element ausgeben, {...} notwendig
echo "ASSOC[def]=${ASSOC[def]}"               # Element ausgeben, {...} notwendig

ASSOC=([a]=v1 [def]=v3 [uvw]=v3)              # Drei Elemente fuellen
echo "ASSOC[a]=${ASSOC[a]}"                   # Element ausgeben, {...} notwendig
echo "ASSOC[bc]=${ASSOC[bc]}"                 # Element ausgeben, {...} notwendig
echo "ASSOC[def]=${ASSOC[def]}"               # Element ausgeben, {...} notwendig
echo "ASSOC[uvw]=${ASSOC[uvw]}"               # Element ausgeben, {...} notwendig
echo "ASSOC[xyz]=${ASSOC[xyz]}"               # Leeres Element
echo "ANZm=${#ASSOC[*]} ASSOC=${ASSOC[*]}"    # Arraylaenge + -Inhalt ausgeben

for N in a def uvw                            # Elemente ausgeben
do
	echo "ASSOC[$N] = ${ASSOC[$N]}"
done
echo "ANZn=${#ASSOC[*]} ASSOC=${ASSOC[*]}"    # Arraylaenge + -Inhalt ausgeben

unset ASSOC[def]                              # Ein Element loeschen
echo "ANZo=${#ASSOC[*]} ASSOC=${ASSOC[*]}"    # Arraylaenge + -Inhalt ausgeben

unset ASSOC                                   # Array loeschen
echo "ANZp=${#ASSOC[@]} ASSOC=${ASSOC[@]}"    # Arraylaenge + -Inhalt ausgeben

#-------------------------------------------------------------------------------
# Skript abbrechen mit Exit-Code 100
#-------------------------------------------------------------------------------
exit 100

