In jedem Unix-Ähnlichen System findet sich die klassische Bourne SHell unter /bin/sh.
Aus diesem Grund scripte ich mit Vorliebe für diese Shell. Dann laufen die Scripte nicht nur auf Linux, sondern auch auf NetBSD, FreeBSD, Solaris, AIX und anderen Unix-Ähnlichen Betriebssystemen.
Bei Entscheideidungen muss man unterscheiden, ob man Zahlen mit oder ohne Kommastellen als Vergleich verwenden möchte!
Die „if“-Anweisung in der BASH kann nicht mit Kommastellen umgehen, in soeinem Fall muss man dann auf AWK zurückgreifen.
if [ "${1}" < 1 ] ; then
GR=klein
elif [ "${1}" < 2 ] ; then
GR=mittel
elif [ "${1}" < 3 ] ; then
GR=gross
else
GR="sehr gross"
fi
echo "${GR}"
# echo "1.5" | awk '{if ($1 < 3) GR="gross" ; if ($1 < 2) GR="mittel" ; if ($1 < 1) GR="klein" ; print $1"="GR}'
1.5=mittel
# echo "1.5" | awk '{if ($1 < 3) GR=3 ; if ($1 < 2) GR=2 ; if ($1 < 1) GR=1 ; print GR}'
2
Unter Linux ist die GNU Bourne-Again SHell unter /bin/bash die Standard-Shell, sie ist in erster Linie für die Konsolenarbeit verbesert worden. So verfühgt sie im Gegensatz zur Bourne SHell über eine Historie.
Die GNU Bourne-Again SHell verfühgt aber auch über zusätzliche Funktionen, die für die Arbeit mit Scripten wichtig sind.
Zum Beispiel funktioniert der kleine Time-Out-Zähler nur in der GNU Bourne-Again SHell, nicht jedoch in der Bourne SHell:
#!/bin/bash
WARTEZEIT="10"
while [ ! -e /tmp/datei ]
do
sleep 1
if [ "${WARTEZEIT}" -gt "0" ] ; then
WARTEZEIT=$((WARTEZEIT - 1))
else
touch /tmp/datei
fi
done
Für die Bourne SHell muss das Kommando bc das rechnen im Script übernehmen:
#!/bin/sh
WARTEZEIT="10"
while [ ! -e /tmp/datei ]
do
sleep 1
if [ "${WARTEZEIT}" -gt "0" ] ; then
WARTEZEIT="$(echo "${WARTEZEIT} - 1" | bc)"
else
touch /tmp/datei
fi
done
oder das Kommando awk:
#!/bin/sh
WARTEZEIT="10"
while [ ! -e /tmp/datei ]
do
sleep 1
if [ "${WARTEZEIT}" -gt "0" ] ; then
WARTEZEIT="$(echo "${WARTEZEIT}" | awk '{print $1-1}')"
else
touch /tmp/datei
fi
done
Dieser Zähler ist zwar etwas umständlich, dafür funktioniert er aber auf jedem aktuellen Uni*-Like Betriebssystem.
Man muss nur darauf achten, dass bc installiert ist. Das kleine Rechenprogramm gibt es aber schon lange für alle Uni*-Like Betriebssysteme.
# i=0;while(("$i"<"10"));do i="$(echo "1+$i"|bc)";echo "$i";done
1
2
3
4
5
6
7
8
9
10
# i=10;while(("$i">"0"));do i="$(echo "$i-1"|bc)";echo "$i";done
9
8
7
6
5
4
3
2
1
0
Sonst kann man auch awk als Rechenknecht verwenden. AWK gibt es für alle Uni*-Like Betriebssysteme und ist eigentlich immer schon mit drauf.
# echo "10"|awk '{for(i=0;i<$1;i++){print i}}'
0
1
2
3
4
5
6
7
8
9
# echo "10"|awk '{for(i=1;i<=$1;i++){print i}}'
1
2
3
4
5
6
7
8
9
10
und jetzt mit fester Zahlenlänge:
# echo "10"|awk '{for(i=1;i<=$1;i++){printf("%.8u\n",i)}}'
00000001
00000002
00000003
00000004
00000005
00000006
00000007
00000008
00000009
00000010
# i=10 ; while (( "$i" > "0")) ; do i="$(echo "$i" | awk '{print $1-1}')" ; echo "$i" ; done
9
8
7
6
5
4
3
2
1
0
# i=10 ; until [ "$i" = "0" ] ; do i="$(echo "$i" | awk '{print $1-1}')" ; echo "$i" ; done
9
8
7
6
5
4
3
2
1
0
Oder man rechnet gleich komplett nur mit dem awk.
# echo "10"|awk '{for(i=$1;0<i;i--){print i}}'
10
9
8
7
6
5
4
3
2
1
und jetzt mit fester Zahlenlänge:
# echo "10"|awk '{for(i=$1;0<i;i--){printf("%.8u\n",i)}}'
00000010
00000009
00000008
00000007
00000006
00000005
00000004
00000003
00000002
00000001
Dieser Befehl ist sehr bequem aber leider gibt es ihn nicht auf jedem System und ausserdem ist er in Scripten manchmal recht zickig.
# seq 1 10 1 2 3 4 5 6 7 8 9 10
# seq 1 10 | tac 10 9 8 7 6 5 4 3 2 1
# seq 1 10 | sed 's/.*/000000&/' | rev | cut -c 1-6 | rev 000001 000002 000003 000004 000005 000006 000007 000008 000009 000010
In diesem Fall wartet die Schleife darauf, dass ein Rechner wieder über das Netz erreichbar ist.
#!/bin/sh
START="1"
while [ "$?" != "0" -o "${START}" = "1" ]
do
START="0"
sleep 1
ping -c1 192.168.0.100
done
DATEI="diese_datei_wird_gleich_angelegt.tgz"
while [ -r "${DATEI}" ]
do
sleep 1
done
nur „180“ Sekunden lang auf die Datei warten:
#!/bin/sh
DATEI="diese_datei_wird_gleich_angelegt.tgz"
ZAEHLER="180"
while [ ! -r "${DATEI}" -a "${ZAEHLER}" -gt "0" ]
do
ZAEHLER="$(echo "${ZAEHLER}"|awk '{print $1-1}')"
sleep 1
done
oder so:
#!/bin/sh
DATEI="diese_datei_wird_gleich_angelegt.tgz"
ZAEHLER="180"
while [ "${ZAEHLER}" -gt "0" ]
do
ZAEHLER="$(echo "${ZAEHLER}"|awk '{print $1-1}')"
if [ ! -r "${DATEI}" ] ; then
ZAEHLER="0"
fi
sleep 1
done
#!/bin/bash
while [ "${#}" -ne "0" ]; do
case "${1}" in
-a)
OPTION_A=${2}
shift
;;
-b)
OPTION_B=${2}
shift
;;
-c)
OPTION_C=${2}
shift
;;
-d)
OPTION_D=${2}
shift
;;
-e)
OPTION_E=${2}
shift
;;
-f)
OPTION_F=${2}
shift
;;
-g1)
OPTION_G1=${2}
shift
;;
-g2)
OPTION_G2=${2}
shift
;;
-h)
echo "
HILFE:
${0} [Option]
-a [wert a]
-b [wert b]
-c [wert c]
-d [wert d]
-e [wert e]
-f [wert f]
-g1 [wert g1]
-g2 [wert g2]
"
exit 1
;;
*)
if [ "$(echo "${1}"|egrep '^-')" ] ; then
echo "Der Parameter '${1}' wird nicht unterstützt!"
fi
shift
;;
esac
done
Auf die Variablen, die in einer gewöhnlichen while-Schleife gesetzt werden,
hat man ausserhalb der Schleife keinen Zugriff, da die while-Schleife
gewöhnlich mit einer Pipe gefüttert wird.
Wegen der Pipe wird aber eine eigene Shell geöffnet und mit ihrem Ende enden auch
die Variablen in ihr.
Deshalb ist die Ausgabe dieses Skripts auch leer:
#!/usr/bin/env bash
VAR=""
echo "Test" | while read ZEILE
do
VAR="${ZEILE}"
done
echo "VAR='${VAR}'"
Dieses Skript liefert dagegen eine Ausgabe:
#!/usr/bin/env bash
VAR=""
while read ZEILE
do
VAR="${ZEILE}"
done < <(echo "Test")
echo "VAR='${VAR}'"
Keine Pipe,
keine Subshell,
keine gestobenen Variablen.