homeUnix & Internet Unix & Shell-Programmierung: shell-Programmierung Prof. Dr. Uwe Schmidt FH Wedel

shell-Programmierung

weiter

weiter

Skript-Programmierung

shell
Kommandosprache
eine vollwertige Programmiersprache
Datentypen
einziger Datentyp: Zeichenreihen, strings
weiter
merke
ungetypte Sprache
gut
flexibel: keine Unterscheidung Daten / Kommandos
weiter
Skripte
Kommandos in Dateien
weiter
Beispiel
#!/bin/bash
 
# liste alle Eintraege
# -a alle, auch .-Dateien
# -l lang
# -t sortiert nach letztem Schreiben
# -r reverse, neuste Datei zum Schluss
 
ls -altr
weiter
vordefinierte Variablen
implizit von der shell beim Aufruf gesetzte Variablen für Parameter, Programmname und return-code
 
$1 ... $9     # 1.-9. Parameter
$*            # alle Parameter 
$@            # alle Parameter: "$@" != "$*"
$0            # Programmname
$$            # Prozessnummer
$?            # return code letztes Kommando
$#            # # Parameter
weiter
Beispiele
cat 118
#!/bin/bash
 
grep $* telefon
weiter
Aufruf
118 FH Wedel
weiter
cat 119
#!/bin/bash
 
grep "$*" telefon
weiter
Aufruf
119 FH Wedel
weiter
cat 120
#!/bin/bash
 
grep -i "$*" telefon
weiter
Aufruf
120 fh Wedel
weiter
weiter
PATH
Umgebungsvariable für Verzeichnisse, in denen nach Programmen (ausführbaren Dateien) gesucht wird.
 
echo $PATH
weiter
which
Programm zum Anzeigen des absoluten Pfads für ein ausführbares Programm.
Aufruf
which -a which
weiter
Test
Werte vordefinierter Variablen
 
#!/bin/bash
 
echo '$0:' $0
echo '$1:' $1
echo '$2:' $2
echo '$3:' $3
 
echo '$*:' $*
echo '$@:' $@
 
echo '$#:' $#
echo '$?:' $?
echo '$$:' $$
 
echo 'for ... in $* do'
for i in $*
do echo $i
done
 
echo 'for ... in $@ do'
for i in $@do echo $i
done
 
echo 'for ... in "$*" do'
for i in "$*"do echo $i
done
 
echo 'for ... in "$@" do'
for i in "$@"
do echo $i
done
Testlauf
bash dollars.sh abc '123 456' '1 2 3 4 5 6'
Resultat
$0: dollars.sh
$1: abc
$2: 123 456
$3: 1 2 3 4 5 6
$*: abc 123 456 1 2 3 4 5 6
$@: abc 123 456 1 2 3 4 5 6
$#: 3
$?: 0
$$: 16551
for ... in $* do
abc
123
456
1
2
3
4
5
6
for ... in $@ do
abc
123
456
1
2
3
4
5
6
for ... in "$*" do
abc 123 456 1 2 3 4 5 6
for ... in "$@" do
abc
123 456
1 2 3 4 5 6
merke
for-Schleifen werden weiter unten beschrieben
weiter

weiter

inline-Dokumente

Texte
als Daten in Skripts
weiter
Beispiel
#! /bin/bash
 
cat <<EOF
ein ganzer Text als
Konstante in einem Skript.
Das inline-Dokument wird beendet
von einer Zeileauf der nur die
frei waehlbare Endemarkehier EOF,
auftaucht
EOF
weiter
gut
Programm und Daten zusammengefasst in einer Datei
weiter
cat 121
#!/bin/bash
 
grep -i -e "$*" <<'End'
FH Wedel      04103-8048-0
Uwe           -45
Nele          8134
Dr.Markus     441777
Auskunft      11833
End
weiter
Aufruf
121 fh Wedel
weiter

weiter

Ausgabeumlenkung

Datenströme
durchnummeriert
0
stdin
1
stdout
2
stderr
weiter
Umlenkung
n> datei
weiter
Beispiel
#!/bin/bash
# finde alle HTML Dateien
 
find / -name '*.html' \
 1> find.out \
 2> /dev/null
weiter
Mischen
von Datenströmen
 
n>&m
weiter
Beispiele
# Ausgabe auf stderr
 
echo "Fehler!!!" 1>&2
 
# stderr nach stdout umleiten
 
find / -name '*.html' \
  > find.out \
  2>&1
 
# Skript-Abbruch
 
echo "ich kann nicht mehr" 1>&2 ; exit 1
 
weiter

weiter

Strukturierte Anweisungen

Schleifen
while Schleifen
while cmd1
do
    cmd2
done
 
 
#--------------------
 
# Zaehlschleife
 
cnt=5
 
while test $cnt -ne 0
do
    echo $cnt
    cnt=`expr $cnt - 1`
done

merkeHochkommata

merke
Rechnen mit expr oder mit Arithmetik in der bash: $(( ... ))
 
count=`expr $count - 1`
 
count=$(expr $count - 1)
 
count=$(($count - 1))
weiter
for Schleifen
for var in list
do
    cmd
done
 
#--------------------
 
for i in *.html
do
    cp $i $i.bak
done
 
#--------------------
 
for i in "$@"
do
    echo $i
done
merke
Mit for-Schleifen wird in Skripten häufiger gearbeitet als mit Zähl- oder while-Schleifen.
weiter
Verzweigungen
if cmd
then
  cmd1
else
  cmd2
fi
 
#--------------------
 
if cmd
then
  cmd1
fi
 
#--------------------
 
if test -f "$file"
then
  echo "$file"
  cat "$file"
else
  echo "$file not found" >&2
fi
 
#--------------------
 
case arg in
  pattern11 | ... | pattern1N)
    cmd1
    ;;
  pattern21 | ... | pattern2M)
    cmd2
    ;;
esac
 
#--------------------
 
# parameter verarbeiten
 
case "$1" in
  -v)
    echo "-v option"
    ;;
  -x | -c)
    echo "-x or -c option"
    ;;
  -*)
    echo "unknown option"
    ;;
  *)
    echo "no option"
    ;;
esac
 
weiter
Tests
Programm: test
 
Alias: [
Beispiele
test n1 -eq n2  # arithm.  =
test n1 -ne n2  # arithm  !=
test n1 -ge n2  # arithm. >=
test n1 -gt n2  # arithm. >
test n1 -le n2  # arithm. <=
test n1 -lt n2  # arithm. <
 
test s1  = s2   # string  =
test s1 != s2   # string !=
 
test -f datei   # ex. file
test -r datei   # datei lesbar
test -w datei   # datei schreibbar
test -x datei   # datei ausfuehrbar
test -s datei   # datei nicht leer
test -d datei   # ex. dir
 
test ! <bed>    # <bed> negiert
 
# 2. Syntax [ ... ]
 
[ n1 -eq n2 ]
...
[ -d datei ]
 
# eingebaute bash operationen
 
[[ n1 -eq n2 ]]
weiter
bedingte Kommandos
cmd1 && cmd2
 
# Kurzform fuer
 
if cmd1
then
    cmd2
fi
 
# Beispiel
 
[ -f file ] && cat file
 
#--------------------
 
cmd1 || cmd2
 
if cmd1
then
    # cmd finished
else
    cmd2
fi
 
# file not found --> exit
 
[ -f file ] || {
    echo "file not found" 1>&2
    exit 1
}
weiter

weiter

Parameter sequentiell verarbeiten

Syntax
shift
weiter
Semantik
1. Parameter wird vergessen
alle anderen werden eine Position nach vorne geschoben
# Parameter wird dekrementiert
weiter
Beispiel
while [ $# -ne 0 ]
do
    echo $# 1. Parameter verarbeiten
    shift
done
weiter

weiter

Parameter bedingt setzten

Syntax
weiter
${variable:-word}
variable leer oder undefiniert -> Wert = word
variable gesetzt -> Wert = Inhalt von variable
weiter
${variable:=word}
default-Zuweisung und Auslesen von variable
weiter
merke
andere Varianten von bedingten Zuweisungen möglich,
aber seltener verwendet
weiter
Beispiel
echo ${var:-nix}
var=etwas
echo ${var:-nix}
 
echo ${par:=was neues}
echo ${par:=nix neues}
weiter

weiter

Kommandos im Hintergrund ausführen

Kommando
mit & abschließen
Wirkung
shell wartet nicht auf die Beendigung des Kommandos
weiter
Beispiele
find / -name '*.html' \
  > find.out \
  2> /dev/null &
 
( sleep 300
  echo "Tee ist fertig" ) &
 
weiter

weiter

Beispiele für Skripte

echo3
5 Beispiele für die Verarbeitung von Parametern
weiter
.1
#!/bin/bash
# echo3 - 1. Version
 
echo "$0 wurde mit $# Parameter(n) aufgerufen."
echo "Die ersten drei Parameter haben die Werte:"
echo "   $1"
echo "   $2"
echo "   $3"
 
weiter
.2
#!/bin/bash
# echo3 - 2. Version
 
echo "$0 wurde mit $# Parameter(n) aufgerufen."
echo "Die ersten drei Parameter haben die Werte:"
echo "   $1"shift
echo "   $1"shift
echo "   $1"
 
weiter
.3
#!/bin/bash
# echo3 - 3. Version
 
echo "$0 wurde mit $# Parameter(n) aufgerufen."
echo "Die ersten drei Parameter haben die Werte:"
 
if test "$1"
then
  echo "   $1"shift
  if test "$1"
  then
    echo "   $1"shift
    if test "$1"
    then
      echo "   $1"
    fi
  fi
fi
 
weiter
.4
#!/bin/bash
# echo3 - 4. Version
 
echo "$0 wurde mit $# Parameter(n) aufgerufen."
echo "Die ersten drei Parameter haben die Werte:"
 
[ $# -gt 0 ] && echo "$1" && shift
[ $# -gt 0 ] && echo "$1" && shift
[ $# -gt 0 ] && echo "$1"
 
weiter
.4a
#!/bin/bash
# echo3 - 4. Version
 
echo "$0 wurde mit $# Parameter(n) aufgerufen."
echo "Die ersten drei Parameter haben die Werte:"
 
[ $# -gt 0 ] && { echo "$1"; shift; }
[ $# -gt 0 ] && { echo "$1"; shift; }
[ $# -gt 0 ] && echo "$1"
 
weiter
.5
#!/bin/bash
# echo3 - 5. Version
 
echo "$0 wurde mit $# Parameter(n) aufgerufen."
echo "Die Parameter haben die Werte:"
 
while [ $# -gt 0 ]
do
   echo "   $1"shift
done
 
weiter
Optionen
Verarbeitung von Optionen mit einem case-Verteiler
 
#!/bin/bash
# Beispiel zur Interpretation von Optionen
# mit einer Schleife und einer case Anweisung
 
while [ $# -gt 0 ]
do
 case "$1" in
  -c | -o) echo "Option -c oder -o"
    ;;
  -*) echo "unbekannte Option $1"
    ;;
  *.c | *.h ) echo "C Quelle $1"
    break
    ;;
  *) echo "unbekannter Parameter $1"
    exit 1
 esac
 shift
done
 
weiter
bundle
ein einfaches Skript zum Bündeln von Textdateien in Form eines sich selbst entpackenden Archivs
weiter
#!/bin/bash
 
#bundle: Dateien zwecks Versand zusammenpacken
 
echo '#!/bin/bash'
echo '# zum Auspacken, sh auf diese Datei anwenden'
 
for i in $*
do
   echo "echo $i 1>&2"
   echo "cat >$i <<'Ende von $i'"
   cat $i
   echo "Ende von $i"
done
 
weiter
2.Version
Bündeln von ganzen Verzeichnisbäumen in Form eines sich selbst entpackenden Archivs
weiter
#!/bin/bash
 
# bundle: Dateien zwecks Versand zusammenpacken
# Ausgabe auf stdout
# erweiterte Version fuer directories
 
# trace Ausgabe
echo "$0 : fuer dateien $*" 1>&2
 
echo '#zum Auspacken, sh auf diese Datei anwenden'
 
for i in $*
do
  if [ -f $i ] && [ -r $i ] && [ -s $i ]
  then
    # trace Ausgabe im erzeugten Skript
    echo "echo $i 1>&2"
 
    echo "cat >$i <<'Ende von $i'"
    cat $i
    echo "Ende von $i"
 
  elif [ -d $i ]
  then
 
    #rekursiver Aufruf
    $$i/*
 
  else
    echo "# datei $i konnte nicht kopiert werden"
 
    # Fehler Ausgabe
    echo "datei $i kann nicht kopiert werden"     1>&2
  fi
done
 
weiter
3.Version
sicheres Bündeln von ganzen Verzeichnisbäumen ohne Probleme mit den Endemarken in inline-Dokumenten
weiter
#!/bin/bash
 
echo '#!/bin/bash'
echo '# zum Auspacken /bin/bash auf diese Datei anwenden'
 
 
for i in $*
do
  if [ -f $i ] && [ -r $i ] && [ -s $i ]
  then
    echo "echo $i 1>&2"
 
    echo "sed 's/^+//' >$i <<'Ende von $i'"
    sed 's/^/+/' $i
    echo "Ende von $i"
 
  elif [ -d $i ]
  then
    echo "[ -d $i ] || mkdir $i"
    $$i/*
 
  else
    echo "# datei $i konnte nicht kopiert werden"
    echo "datei $i kann nicht kopiert werden" 1>&2
  fi
done
 
weiter
4.Version
sicheres Bündeln von ganzen Verzeichnisbäumen ohne Probleme mit Sonderzeichen in Dateinamen
weiter
Problem
Sonderzeichen in Dateinamen
touch "a b c"
 
for i in a*
do
  ls -l $i
done
 
for i in a*
do
  ls -l "$i"
done
weiter
Lösung
für bundle
#!/bin/bash
# Bourne shell
 
# skript sicher gemacht gegen Sonderzeichen
# in Dateinamen
 
echo '#!/bin/bash'
echo '# zum Auspacken /bin/bash auf diese Datei anwenden'
 
for i in "$@"
do
  if [ -f "$i" ] && [ -r "$i" ] && [ -s "$i" ]
  then
    echo "echo \"$i\" 1>&2"
    echo "sed 's/^+//' > \"$i\" <<'Ende von $i'"
    sed 's/^/+/' "$i"
    echo "Ende von $i"
  else
  if [ -d "$i" ]
  then
    echo "[ -d \"$i\" ] || mkdir \"$i\""
    for j in "$i/"*
    do
      $"$j"
    done
  else
    echo "# datei $i konnte nicht kopiert werden"
    echo "datei $i kann nicht kopiert werden" 1>&2
  fi
  fi
done
 
weiter
merke
schrittweise Verfeinerung und Vervollständigung von Skripten

weiter

Modularisierung

Problem
Skripte in Funktionen aufteilen
1.Lösung
pro Funktion ein separates Skript
weiter
schlecht
unhandlich
weiter
2.Lösung
Funktionen
weiter
Beispiel
#!/bin/bash
 
function quit () {
    local rc=${1:-0}
    echo "program terminated (rc=$rc)" 1>&2
    exit $rc
}
 
function hello () {
    echo Hello $1!
}
 
hello you
quit
weiter
2. Beispiel
#!/bin/bash
# Bourne shell
 
# skript mit pack Funktion
 
echo '#!/bin/bash'
echo '# zum Auspacken /bin/bash auf diese Datei anwenden'
 
function pack () {
    if [[ -f "$1" ]] && [[ -r "$1" ]] && [[ -s "$1" ]]
        then
        echo "echo \"$1\" 1>&2"
        echo "sed 's/^+//' > \"$1\" <<'Ende von $1'"
        sed 's/^/+/' "$1"
        echo "Ende von $1"
    else
        if [[ -d "$1" ]]
            then
            echo "[[ -d \"$1\" ]] || mkdir \"$1\""
            for j in "$1/"*
              do
              pack "$j"
            done
        else
            echo "# datei $1 konnte nicht kopiert werden"
            echo "datei $1 kann nicht kopiert werden" 1>&2
        fi
    fi
}
 
set -x
 
for f in "$@"
do
  # loesche optionalen / am Ende des Namens
  f=$(echo "$f" | sed -e 's|/$||')
 
  pack "$f"
done
 
weiter
merke
Der Stream-Editor sed wird im Kapitel über reguläre Ausdrücke beschrieben.
Eigenschaften
Funktionen werden aufgerufen wie Kommandos.
Funktionen werden in dem gleichen Prozess ausgeführt wie das rufende Kommando.
Skripte würden in einem Subprozess ausgeführt werden.
Funktionsparameter können mit $1, ..., $n referenziert werden.
$0 wird nicht verändert.
Variablen global zur Funktion können beliebig genutzt werden.
lokale Variablen müssen mit local deklariert werden.
return beendet die Ausführung einer Funktion.
Das Schlüsselwort function ist optional.
weiter
Beispiel
Eine Kreuzreferenz-Liste für Bezeichner in einem C-Programm
 
weiter

weiter

shell Eigenschaften

Filter
shell ist auch ein Filter
Beispiele
bash scriptFile
 
bash < scriptFile
 
bash -c 'cmd'
 
genCmd | bash
 
#--------------------
 
echo 'ls -l' > lll
 
bash lll
 
bash < lll
 
bash -c 'ls -l'
 
echo 'ls -l' | bash
weiter
Optionen
-x
Kommando trace
-n
nur Syntaxcheck
-u
nicht initialisierte Variablen überprüfen
-v
verbose: vor der Ausführung Ausgabe jedes Kommandos
weiter
2.Beispiel
# bash als Filter
#
# backup Kopie aller .html files
 
find . -name '*.html' \
  | sed -e "s|\(.*\)|cp '\1' '\1.bak'|" \
  | bash
 
#--------------------
 
# geht auch direkt mit find
 
find . -name '*.html' -exec cp "'{}'" "'{}.bak'" ';'
weiter
rapid prototyping
schnelles Erstellen eines lauffähigen Prototypen
weiter

Letzte Änderung: 10.11.2014
© Prof. Dr. Uwe Schmidt
Prof. Dr. Uwe Schmidt FH Wedel