Bash Programmierung: Unterschied zwischen den Versionen

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen
Zeile 19: Zeile 19:
 
*[[Rechnen mit der Bash]]
 
*[[Rechnen mit der Bash]]
  
=Die while-Schleife=
+
*[[Bash Die while-Schleife]]
==Einfache Form==
 
Die while-Schleife wird so lange durchlaufen, bis der Returncode ungleich null ist.
 
*cat proggi
 
<syntaxhighlight>
 
#!/bin/bash
 
while [ $# -ge 1 ]
 
do
 
  echo $1
 
  echo $#
 
  shift
 
done
 
</syntaxhighlight>
 
  
*./proggi blau gelb gruen
 
blau
 
3
 
gelb
 
2
 
gruen
 
1
 
 
Darstellung als Struktogramm nach Nassi / Shneiderman:
 
 
[[Image:while.jpg]]
 
 
Beispiel:
 
<syntaxhighlight>
 
#!/bin/bash
 
COUNTER=$1
 
while [ $COUNTER -ge 1 ]
 
  do
 
  echo $COUNTER
 
  COUNTER=$(($COUNTER-1))
 
done
 
echo "BUMM BUMM"
 
</syntaxhighlight>
 
*./countdown 5
 
5
 
4
 
3
 
2
 
1
 
BUMM BUMM
 
 
==Sonderform von while==
 
Die Variable SUX wird nacheinander mit jeder Zeile der Datei
 
/etc/passwd belegt, bis die letzte Zeile der Datei /etc/passwd erreicht ist.
 
<syntaxhighlight>
 
#!/bin/bash
 
while read SUX
 
do
 
echo $SUX
 
done  <  /etc/passwd
 
</syntaxhighlight>
 
Selbstgebautes cat
 
<syntaxhighlight>
 
#!/bin/bash
 
while read ZEILE
 
do
 
  echo $ZEILE
 
done < $1
 
</syntaxhighlight>
 
Selbstgebautes tac
 
<syntaxhighlight>
 
#!/bin/bash
 
COUNT=0
 
while read ZEILE
 
do
 
FELD[$COUNT]=$ZEILE
 
COUNT=$(($COUNT+1))
 
done < $1
 
while [ $COUNT -ge 0 ]
 
do
 
echo ${FELD[$COUNT]}
 
COUNT=$(($COUNT-1))
 
done
 
</syntaxhighlight>
 
 
=Die until-Schleife=
 
=Die until-Schleife=
  

Version vom 24. Mai 2023, 18:31 Uhr

Bash Basics

Die until-Schleife

Die until-Schleife wird so lange durchlaufen, bis der Returncode der Abbruchbedingung gleich null ist.

	until test $# -eq 0
	do
	     echo $1
	     shift
	done

Darstellung als Struktogramm nach Nassi / Shneiderman:

Until.jpg

Die for-Schleife

Standard For Schleife

Bei der for-Schleife wird bei jedem Durchlauf der Schleifenvariablen ein Wert aus einer angegebenen Liste zugewiesen; die Liste wird dabei von links nach rechts durchlaufen. Nach der letzten Wertzuweisung terminiert die for-Schleife.

  • cat fussball
 #!/bin/bash
 for CLUB in fck bvb schalke bmg
  do
   echo $CLUB
 done
  • ./fussball
fck
bvb
schalke
bmg

Darstellung als Struktogramm nach Nassi / Shneiderman:

For.jpg

For Schleife mit Stellungsparametern

Wird keine Liste angegeben, wird standardmäßig die Liste der Stellungsoperanden benutzt. Folgende Anweisungen sind äquivalent

#!/bin/bash
for LAUF in $*
 do
  echo $LAUF
 done

Kurzform :

for LAUF 
 do
  echo $LAUF
 done

For Schleife mit Dateien aus dem aktuellen Verzeichnis

Der Stern würde durch alle Dateien des aktuellen Verzeichnisses ersetzt werden. Daraus folgt, dass der Name jeder Datei nacheinander in die Variable LAUF geschreiben wird. Die Anzahl der Schleifenläufe ist identisch mit der Anzahl von Dateien.

 
#!/bin/bash
for LAUF in *
do
 echo $LAUF
done

Hier die Variante mit einem grossen K

#!/bin/bash
for LAUF in K*
do
 echo $LAUF
done

For Schleife im C Stil

Mit Bash-Version 2.0.4 wurde die for-Schleife um eine an die Programmier-sprache C angelehnte Syntaxvariante erweitert:

for ((Initialisierung der Laufvaribale; Laufbedingung; Veränderung der Laufvariable))
do 
Kommando
done 
  • cat foor
 #!/bin/bash
 for ((I=1;I<5;I++))
 do
 echo $I
 done
  • ./foor
1
2
3
4

Steuerung der Ablaufanweisungen

exit n

Der aktuelle Prozess und damit auch die bash werden abgebrochen. Für n kann eine Zahl zwischen 0 und 255 angegeben werden; damit kann der Returncode des Prozesses festgelegt werden, der an den aufrufenden Prozess übergeben wird.

Zur Schleifensteuerung können die Befehle continue und break verwendet werden. Sie dürfen nur zwischen den Schlüsselwörtern do und done stehen.

continue n

Der aktuelle Schleifendurchlauf wird abgebrochen, um mit dem nächsten Durchlauf zu beginnen. Bei Verschachtelungen kann durch Angabe einer Ganzzahl in der n-ten Schleifenebene angesetzt werden.

#!/bin/bash
for CLUB in fck bvb bayern fcs
 do
  if [ $CLUB = "bayern" ]
   then
     echo "zeig ich nicht an"
     continue
     exit
   fi
 echo $CLUB
 done
  • ./fussball
fck
bvb
zeig ich nicht an
fcs

Select

Mit dem Befehl bash select können verschiedene Arten von Menüerstellungsaufgaben, das Erstellen einer menübasierten Listen, das Erstellen eines Menüs aus Dateiinhalten usw. ausgeführt werden.


#!/bin/bash
select auswahl in Punkt1 Punkt2 Punkt3 Punkt4
do
   echo "Ihre Auswahl war : $auswahl"
done
#!/bin/bash
PS3="Datei zum Editieren auswählen : "
select AUSWAHL in *.sh exit
do
   case "$AUSWAHL" in
      exit)
           echo "exit" 
           break
          ;;
        "")
           echo "$REPLY: Ungültige Auswahl" 
           ;;
         *)
             if [ -d "$AUSWAHL" ]
              then
                echo "Verzeichnis kann nicht editiert werden"
                continue
              else
                $EDITOR $AUSWAHL
               fi
              break
            ;;
   esac
done



break n

Die aktuelle Schleife wird abgebrochen, danach wird mit der ersten Anweisung nach der Schleife weitergemacht. Bei Verschachtelungen wird auf der n-ten Schleifenebene aufgesetzt.

Anmerkung: Ein sinnvoller Einsatz dieser Konstrukte liegt in der Behandlung von Ausnahmen (Fehler). Intensiver Einsatz macht die Programme unleserlich und schwer kontrollierbar. Daher ist eine sparsame Verwendung empfehlenswert.

#!/bin/bash 
while true
 do
  test -f /tmp/sux && break  
  echo "unn weiter"
  sleep 3
 done
 echo  "und tschuess"

Funktionen

bash funktion

Signalbehandlung

Signale bei der Programmierung der bash

Es existieren verschiedene Möglichkeiten, auf welchem Wege Signale gesendet werden können:

  1. von aussen:
    1. Benutzer (< DEL >, < CTRL >|, etc.)
    2. Prozesse (kill, alarm)
  2. von innen:
    1. Programmfehler (Adressfehler, ungültiger Befehl, Division durch 0, etc.)

Signale dienen der Interprozesskommunikation. Diese Nachrichten beschränken sich allerdings auf die Übertragung eines einzigen Wertes.

Von den Befehlen trap und kill werden folgende Signale verwendet:

Signalnummer Bedeutung
0 Beenden von bash
SIGHUP 1 Logoff von einer Datensichtstation
SIGINT 2 Drücken der Taste < DEL >
SIGQUIT 3 Drücken der Taste < CTRL > + c
SIGKILL 9 kill: unbedingter Prozessabbruch
SIGTERM 15 Programmbeendigung

Reaktion eines Prozesses auf den Empfang eines Signals

  • Der Prozess beendet sich (meist Standardeinstellung).
  • Der Prozess ignoriert das Signal. (Ausnahme: SIGKILL)
  • Der Prozess fängt das Signal ab, d.h. er leitet eine selbst definierte Reaktion ein.

Der Befehl trap

Funktionen:

Signalbehandlung setzen

(Nach Beendigung der bash werden die betreffenden temporären Dateien gelöscht)

  • trap 'rm *.tmp' 0
  • trap 'who; exit 1' 2 3
Liefern von Informationen über gesetzte Signalbehandlung
  • trap
Zurücksetzen der Signalbehandlung
  • trap 2 3
Import von Signalen
  • trap : 2 3
  • trap 2 3
Demonstriert die Funktion trap zum Abfangen von Signalen
#!/bin/bash
trap 'echo trap ausgelöst' 2
i=0
while [ $i -lt 5 ]
do
   echo "Bitte nicht stören!"
   sleep 2
   i=`expr $i + 1`
done

Bemerkung: Die Signalbehandlung selbst wird nicht an Kindprozesse weitervererbt. Das Ignorieren von Signalen hingegen wird weitervererbt.

Weitere Möglichkeiten der Bash-Shell

Alias-Namen

Filedeskriptoren

Schreibenden Deskriptor

anlegen
  • exec 5> /tmp/five
rein schreiben
  • echo eins >&5
  • echo zwei >&5
  • echo drei >&5
ausgeben
  • cat /tmp/five
aufheben
  • exec 5>&-
führt zu Fehler
  • echo vier >&5

Lesender Deskriptor

anlegen
  • exec 7< /etc/hosts
auslesen
  • cat <&7
geht nur einmal
  • cat <&7

Gleichzeitiges Lesen aus verschiedenen Dateien

#!/bin/bash
exec 3< /etc/passwd
exec 4< /etc/shadow
while true 
 do 
  read var3 <&3 
  read var4  <&4 
  echo passwd  $var3
  echo shadow $var4 ; 
  test -z $var4 && break 
 done

Gleichzeitiges Lesen aus Datei und Standardeingabe

#!/bin/bash
exec 3< $1
while read line <&3
do
   echo $line
   printf "Eine weitere Zeile einlesen? [j/n] : "
   read REPLY
   test "$REPLY" = "n"  && break
done

Bearbeiten von Farben

Um die Farben in der Shell zu ändern, müssen wir bestimmte Zeichenfolgen senden. Die Zeichenkette \033\13301;31m würde z.B. alles Weitere in Rot ausgeben.

Format: \033\133;m

Diese Methode kann allerdings beim Setzen der Variable $PS1, die den Prompt kontrolliert, dazu führen, dass der Zeilenumbruch falsch berechnet wird. Deshalb ist in diesem Fall der Einschluss in \[ \] erforderlich.

Format: \[\033\133;m\]

Um mit dem Farbigen aufzuhören und wieder normal zu schreiben sendet man einfach folgende Zeichenfolge:

\033\1330m

Textdekorationen:

00 - Schmaldruck
01 - Keine
02 - dunkle Version der Farbe
04 - Unterstreichen
05 - Invertieren

Farben:

30 - Schwarz
31 - Rot
32 - Grün
33 - Gelb
34 - Blau
35 - Lila
36 - Cyan
37 - Grau

Hintergründe färben:

40 - Schwarz
41 - Rot
42 - Grün
43 - Gelb
44 - Blau
45 - Lila
46 - Cyan
47 - Grau

Austesten wie es dann genau aussieht kann man das mit den folgenden Befehlen:

for i in `seq 40 47`;do echo -e "Farbnummer:\033\13301;"$i"m $i \033\01330m";done
for i in `seq 30 37`;do echo -e "Farbnummer:\033\13301;"$i"m $i \033\01330m";done

getopts

#!/bin/bash
function examine()
{
FILE=$1
shift
echo "Rights on $FILE"
for k in $*
do
case $k in
 u) echo USER : $(ls -l $FILE | cut -c 1-3) ;;
 g) echo GROUP: $(ls -l $FILE | cut -c 4-6) ;;
 o) echo OTHER: $(ls -l $FILE | cut -c 7-9) ;;
esac
done
}
while getopts ugof: opt
do
   case $opt in
       u) OPT="${OPT} u";;
       g) OPT="${OPT} g";;
       o) OPT="${OPT} o";;
       f) DAT=$OPTARG;;
       ?) echo "USAGE: $0 -ugo -f FILE"; exit 2 ;;
   esac
done
examine $DAT $OPT
Erklärung
  • Das Program kann mit den Optionen -u -g -o und -f Datei aufgerufen werden.
  • Die Optionen ugo werden in der Variable $OPT "gesammelt".
  • Alle Optionen werden an die Funktion examine übergeben.
  • Die Optionen werden oben getrennt und je nach vorhandener Option werden Anweisungen ausgeführt.


printf

Formatierte Ausgabe mit printf

Im einfachsten Fall wird ein fester Text auf dem Bildschirm ausgegeben:

  • printf("Dies ist ein einfaches Beispiel");

Der Text kann auch Sonderzeichen (z. B. Zeilenumbrüche) enthalten:

  • printf("Hier werden \n zwei Zeilen ausgegeben!");

Die Zeichensequenz \n bewirkt einen Sprung an den Anfang der folgenden Bildschirmzeile. Weitere gebräuchliche Sonderzeichen sind:

\n Sprung an den Anfang der folgenden Bildschirmzeile
\b Gehe ein Zeichen zurück
\a Akustisches Signal
\r Sprung an den Anfang der aktuellen Bildschirmzeile
\\ Ausgabe des Gegenschrägstrichs "\" (Backslash)
%% Ausgabe des Prozent-Zeichens "%"
\" Ausgabe eines doppelten Anführungszeichens
\t Sprung zur nächsten Tabulatorposition

Sollen aktuelle Variablenwerte ausgegeben werden, werden in den Aufruf der

Funktion printf entsprechende „Platzhalter“ eingefügt:

  • int x = 10;
  • printf("Der Wert %d wurde der Variablen x zugewiesen.", x);

Auf dem Bildschirm erfolgt die Ausgabe „Der Wert 10 wurde der Variablen x zugewiesen“, es wird also der Platzhalter %d durch den aktuellen Wert der Variablen x ersetzt. Es ist möglich, mehrere Variablen zugleich auszugeben:

  • int x = 123, y = 234;
  • printf("x = %d und y = %d", x, y);

Die Ausgabe lautet in diesem Fall „x = 123 und y = 234“. Für jede Variable ist ein eigener Platzhalter (hier: %d) notwendig. Die auszugebenden Variablen werden durch Kommas getrennt aufgelistet. Für jeden Platzhalter muss dabei eine Variable angegeben werden (hier: x, y). Es ist zu beachten, dass der Platzhalter zum Typ der auszugebenden Variablen passt (z. B. dient %d zur Ausgabe einer Variablen des Typs int, short oder long). Weitere Platzhalter sind:

%d, %i int, short, long Ganze Zahl
%x, %X int, short, long Ganze Zahl, Ausgabe als Hexadezimalzahl
%f float, double Fließkommazahl
%e, %E float, double Fließkommazahl, Ausgabe im Exponentialformat
%c char Einzelnes Zeichen (Buchstabe, Ziffer, …)
%s char* Zeichenkette („String“)
Beispiel
  • int i = 10; double d = 22.22; char c = 'X';
  • char* str = "abcdefg...";
  • printf("Beispiel zu printf:\n");
  • printf("%d, %f, %c\n", i, d, c);
  • printf("%s", str);

Es kann die Breite des Ausgabebereichs angegeben werden. So wird mit %10d eine ganze Zahl rechtsbündig in einem Bereich von 10 Zeichen Länge ausgegeben: int i = 123;

  • printf("->%d<-\n", i);
  • printf("->%4d<-\n", i);
  • printf("->%5d<-\n", i);

Bei der Ausgabe von Fließkommazahlen kann zusätzlich zur Länge des Ausgabebereichs die Anzahl der Nachkommastellen eingestellt werden:

  • float f = 123.625;
  • printf("->%f<-\n", f);
  • printf("->%.2f<-\n", f);
  • printf("->%10.0f<-\n", f);
  • printf("->%10.1f<-\n", f);
  • printf("->%10.2f<-\n", f);
  • printf("->%10.3f<-\n", f);
  • printf("->%10.4f<-\n", f)

Beispielskript

#!/bin/bash
for DIR in $(df -t ext4  | awk 'NR>1 {  print $6 }')
 do
  PROZENT=$(df -t ext4 $DIR | awk 'NR>1 {  print $5 }')
  PRO=$(echo $PROZENT | tr -d "%")
   let KI=PRO*20/100
   let MI=20-KI
    K="####################"
    M='--------------------'
   printf "%-10s%-4s%.${KI}s%.${MI}s" $DIR $PROZENT $K $M
    echo
 done

Links

Das neue Test Kommando

  • "[[" ist Bashs Verbesserung des "[" Befehls.
  • Es ist die bessere Wahl, wenn Sie Skripte schreiben, die auf Bash abzielen. Meine Favoriten sind:
  • Es ist eine syntaktische Funktion der Shell, daher weist sie ein besonderes Verhalten auf, das "[" nicht hat.
  • Variablen müssen nicht mehr quotiert werden, da leere Zeichenfolgen und Zeichenfolgen mit Leerzeichen intuitiver behandelt werden.
  • Zum Beispiel müssen Sie mit "[" schreiben.
if [ -f "$ FILE"]
  • um leere Zeichenfolgen oder Dateinamen mit Leerzeichen richtig zu behandeln. Mit "[[" sind die Anführungszeichen unnötig:
if [[ -f $ FILE ]]
  • Da es sich um eine syntaktische Funktion handelt, können Sie && und || verwenden Operatoren für Boolesche Tests und <und> für Zeichenfolgenvergleiche.
  • [ kann dies nicht tun, da es sich um einen regulären Befehl handelt und &&, ||, <und> nicht als Befehlszeilenargumente an reguläre Befehle übergeben werden.
  • Es hat einen wunderbaren Operator = ~, um Übereinstimmungen mit regulären Ausdrücken zu erstellen. Mit [ könntest du schreiben
if ["$ ANSWER" = y -o "$ ANSWER" = yes]
  • Mit [[ können Sie dies als schreiben
if [[ $ ANSWER = ~ ^ y (es)? ]]
  • Sie können sogar auf die erfassten Gruppen zugreifen, die in BASH_REMATCH gespeichert sind.
  • Zum Beispiel wäre $ {BASH_REMATCH [1]} "es", wenn Sie oben ein vollständiges "ja" eingeben.
  • Sie erhalten die Mustererkennung aka Globbing kostenlos.
  • Vielleicht sind Sie weniger streng im Schreiben von Ja. Vielleicht bist du okay, wenn der Benutzer y-irgendetwas eingibt. Haben Sie sich versichert:
  • wenn $ ANSWER = y *

Links