#!/bin/bash
# In Zeile 1 wird der Interpreter festgelegt - auch möglich:
# bash -> sh, csh, tcsh, ...

# Teil 1: Variablendefinition:
# Teil 2: Manipulation von Variablen:
# Teil 3: Linux Umgebung
# Teil 4: Grundlegende Tools
# Teil 5: Arbeiten mit entfernten Maschinen
# Teil 6: Pipes etc.
# Teil 7: Schleifen
# Teil 8: Funktionen
# Teil 9: Bedingungen
# Teil 10: Arrays

########################################################
# Teil 1: Variablendefinition
########################################################

# WICHTIG:  * Keine(!) Leerzeichen um =
# 			* Es gibt nur den Variablentyp "string"
#			* erlaubt: nur Buchstaben und Zahlen _ Erstes Zeichen IMMER Buchstaben
#			* keine reservierten Wörter oder Symbole
A=Text
B=5
CLOWN="Text mit Leerzeichen"

# Ausgabe eines strings mit echo; Variablen immer mit $ ansprechen
echo $A
echo $B
echo "$A $CLOWN"
echo "${A}e ohne Sinn und Verstand"
echo '${A}e ohne Sinn und Verstand'

# Das Ersetzen von Variablen und Sonderzeichen in bash nennt man bash-expansion - findet bei "" statt, bei '' nicht
# Mehr zu bash-expansion: https://www-user.tu-chemnitz.de/~hot/unix_linux_werkzeugkasten/bash.html#expand


########################################################
# Teil 2: Manipulation von Variablen
########################################################

# String substitutionen
text="Text ohne Sinn und ohne Verstand"
# Ersetze alle Treffer
echo ${text//ohne/mit}
# Ersetze nur den ersten Treffer
echo ${text/ohne/mit}
# Enternen von Zeichen; hier das Leerzeichen
echo ${text// /}

dateiname=my_file.dat
# Extrahiere den suffix
echo ${dateiname%.*}
# Extrahiere den Dateinamen ohne suffix
echo ${dateiname##*.}

# Laenge eines Strings
echo ${#dateiname}

########################################################
# Teil 3: Linux Umgebung
########################################################

# Linux besitzt zahlreiche vordefinierte Variablen: $HOME, $USER, $PWD, $PATH, uvm.
echo "Ich bin $USER und meine Dateien liegen im Pfad $HOME"
echo "Ich bin $BASH_VERSION und durchsuche $PATH nach ausfuehrbaren Dateien"

# Hinzufuegen eines neuen Ordners zur PATH variable
export PATH=$PATH:/pfad/zum/neuen/Ordner
# export macht Umgebungsvariable


########################################################
# Teil 4: Grundlegende Tools
########################################################

# Anzeigen des Inhalts des aktuellen Ordners
ls
ls $HOME
ls ~/
ls ~/PUBLIC
# Anzeigen des gesamten Inhalts
ls -a
# Anzeigen von Details
ls -l

# Einfache Ordnererstellung, liefert Fehler bei mehrfacher Ausgabe
mkdir ordner
# '-p' Option ermoeglicht es, verschachtelte Ordner zu erstellen
# Keine Fehlermeldung, falls der Pfad schone existiert.
mkdir -p ordner/subpath

# Wechsel in anderen Ordner
cd ordner/subpath
# Wechsel ins aktuelle Verzeichnis (Achtung, hier passiert nichts)
cd .
# Wechsel in uebergeordnete Verzeichnisse
cd ../../
# Wechsel ins Homeverzeichnis
cd
# Wechsel in das letzte besuchte Verzeichnis
cd -

# Verschieben/Umbenennen
mv neuer_ordner ordner_2

# Kopieren
# Beim Kopieren von Ordnern die '-r' Option angeben
cp -r ordner neuer_ordner

# Alternatives Kopieren
rsync -r ordner noch_ein_neuer_ordner
# Bei Verwendung von Symlinks: '-l' verwenden

# Loeschen
# Beim Loeschen von Ordnern die '-r' Option angeben
rm -r ordner_2
# ACHTUNG: Keine Wiederherstellmoeglichkeit
# ACHTUNG: Vorsicht bei der Verwendung von Variablen.
#          Bei Programmierfehler kann schnell das gesamte HOME-Verzeichnis geloescht werden.
#          Verwendung von 'set -u' empfehlenswert. Dann stoppt die Ausfuehrung bei leeren Variablen.

# Anzeigen einer Datei im Terminal
cat ~/.bash_history

# Anzeigen einer Datei rueckwaerts im Terminal
tac ~/.bash_history

# Anzeigen der ersten 20 Zeilen
head -n 20 ~/.bash_history

# Anzeigen der letzten 20 Zeilen
tail -n 20 ~/.bash_history

# Schrittweises Anzeigen einer Datei 
less ~/.bash_history   # beenden mit q # suchen zeigen

# Anzeigen der Zeilen mit einem bestimmten Muster
grep ls ~/.bash_history
grep "model name" /proc/cpuinfo

# Anzeigen der Dateigroeße
du -sh ~/.bash_history

# Anzeil von Zeilen, Woerter, Zeichen in Datei
wc ~/.bash_history

# Suchen von Dateien
find /etc/ -name "*.rc"

# Teil eines Strings extrahieren
echo "abc def" | cut -d " " -f 1 

# Ausfuehren von Programmen im Hintergrund
# Ermoeglicht Weiterarbeiten im Terminal
cat ~/.bash_history | sort | tail > ausgabe.txt &
eog &
# Anzeigen der Hintergrundprozesse
jobs

# Einfaches Rechnen mit Bash
echo $((100+2/2))
echo $((3/2))  # nur Ganzzahlen
echo $((RANDOM%10))  # Zufallszahlen von 0 bis 9
echo "2.4/2" | bc     # liefert 1
echo "2.4/2" | bc -l  # liefert 1.2
bc -l <<< "2.4/2"

########################################################
# Teil 5: Arbeiten mit entfernten Maschinen
########################################################

# Anmelden an einer entfernten Maschine
ssh polaris2.physik.tu-chemnitz.de

# scp datei $USER@entfernte_Maschine:path
# rsync datei $USER@entfernte_Maschine:path

########################################################
# Teil 6: Pipes etc.
########################################################

# Pipes
cat ~/.bash_history | grep ls
# Ausgabe in Datei (Datei neu schreiben)
cat ~/.bash_history > shrinked_history
# Ausgabe in Datei (anhaengen an Datei)
cat ~/.bash_history >> shrinked_history
# Beliebige Verkettungen sind denkbar
cat ~/.bash_history | sort | tail > ausgabe.txt
# stderr in Datei schreiben
# 1>/dev/null verwirft stdout
cat ~/.bash_history 2>&1 | tee -a errors.log
# Dateien finden und an weiteres Programm (hier stat) mittels xargs uebergeben 
find -name '*pdf' | xargs stat

# Subshells
divident=2.4
divisor=2
echo "Das Ergebnis ist $(echo "$divident/$divisor" | bc -l)"
# Alternativer Syntax (das obige ist empfehlenswert)
wc -l `find /etc/ -name "*.rc"`

# Ausfuehren zweier Befehle
{cd /; ls; cd - }  # wechselt nach '/', macht dort ls und bleibt dort

# zweites Semikolon is notwendig
(cd /; ls )  # wechselt nach '/' und macht dort ls, wechselt dann wieder zurueck


########################################################
# Teil 7: Schleifen
########################################################
# Mehrzeilige Version
for file in file_1 file 2 file_3
do
    echo $file
done

# Einzeilige Version
for file in *; do echo $file; done

# C-like for loop
for ((index=0; index<100; index++)); do echo $index; done

# Alternativen:
for index in {00..99}; do echo $index; done
# Wenn Start oder Ende durch Variable bestimmt sein soll
start=0
end=99
for index in $(seq $start $end); do echo $index; done

# float values
for index in $(seq $start 0.1 $end); do echo $index; done
# Falls seq Kommas als Separator nutzt, aber Punkte gewuenscht sind,
# so muss
export LANG=en_US
# vor dem seq-Aufruf gesetzt werden

# Zeilenweises Lesen einer Datei
cat ~/.bash_history | while read line; do echo $line; done
# Numerieren jeder einzelnen Zeile
index=0; cat ~/.bash_history | while read line; do echo $index $line; index=$((index+1)); done

########################################################
# Teil 8: Funktionen
########################################################

# Einschub scripte
echo "ls" > ls_file.sh
bash ls_file.sh

echo -e "#/bin/bash\nls" > ls_file.sh
chmod +x ls_file.sh  # auch +r +w -r -w -x
./ls_file.sh

# Einfache Funktionsdefinition
function my_name(){
    echo $USER
}
my_name

# Auf 'function' kann verzichtet werden,
# schadet aber der Lesbarkeit

# Funktionsdefinition mit Argumenten
# Zugriff auf Argument:
#    $1 : erstes Argument
#    $* : alle Argumente
#    $@ : alle Argumente ab dem ersten
#    $# : Anzahl der Argumente
function divide(){
    quotient=$(echo "$1/$2" | bc -l)
    echo $quotient
    }
result=$(divide 2.4 2)
echo $result


########################################################
# Teil 9: Bedingungen
########################################################

# Viele Operationen moeglich wie z.B. -eq -ne -lt, etc.
if [[ 1 -eq 1 ]]; then echo "Alles gut."; else echo "Die Hoelle ist zugefroren."; fi

# Pruefen auf Existenz von Datei
if [[ -e "~/.bash_history" ]]; then echo "History exists"; fi
# Pruefen auf Existenz von Ordner
if [[ -d "~/.bash_history" ]]; then echo "History exists"; fi  # liefert False

# Pruefen ob string einen substring enthaelt
string="Text mit Leerzeichen"
search_string="Text"

if [[ $string == *"$search_string"* ]]; then echo "Der String '$search_string' ist in '$string'"; fi

# Hinweis: '[[' ist ein Programm, welches entweder 0 (true) oder 1 (false) zurueckgibt
# Daher laeest sich if auch leicht mit anderen Programmen nutzen
if grep -q "ls" ~/.bash_history; then echo "ls wurde schonmal ausgefuert"; fi

# "expression && cmd": fuehre cmd aus, falls expression true zurueckgegeben hat
grep -q "ls" ~/.bash_history && echo "ls wurde bereits verwendet"
# "expression || cmd": fuehre cmd aus, falls expression false zurueckgegeben hat
grep -q "lss" ~/.bash_history || echo "lss wurde noch nie verwendet"

########################################################
# Teil 10: Arrays
########################################################

# Initialisiere leeres Array
physiker=()
physiker+=("planck")
physiker+=("feynman")

# Gibt das erste Element aus
echo $physiker

# Gibt alle Elemente aus
echo ${physiker[@]}

# Zugriff auf ein bestimmtes Element
echo ${physiker[1]}

# Laenge des Arrays
echo ${#physiker[@]}

# String zu Array konvertieren
string="curie newton hawking"
physiker2=($string)

# Kombinieren von arrays
alle_physiker=(${physiker[@]} ${physiker2[@]})

# Loeschen von Elementen
unset alle_physiker[3]
# Achtung: Mehrfaches Ausfuehren aendert nichts am Array,
# da das Element mit dem Key "3" bereits geloescht wurde
