LINUX

Das universelle Betriebssystem

Eine Einführung - Teil 4

Deutsche Angestellten Akademie

Bash Scripting

Einführung und Übung

Bash Scripting - Warum sollte ich das tun??

  • Automatisierung
  • Vereinfacht komplizierte Vorgänge
  • Verringert den Fehlerfaktor „Mensch“
  • YOLO !!1!

Grundlegende Mechanismen

Begriffe

Wurzelverzeichnis / (engl. root) Höchstes Verzeichnis im Verzeichnisbaum
Aktuelles Arbeitsverzeichnis Das Verzeichnis, in dem Sie sich im Augenblick befinden
Vollständige Pfadangabe Ein Pfadname beginnend mit / (Wurzel); alle anderen Verzeichnisse werden ebenfalls mit einem / getrennt.
Relative Pfadangabe Der Pfad ist relativ zum aktuellen Arbeitsverzeichnis; hierbei wird kein voranstehendes / verwendet.
Vollständiger Dateiname Pfadangabe inklusive Angabe zur entsprechenden Datei (bspw. /home/you/Dokumente/brief.txt)
Vollständiger Pfadname Pfadangabe zu einem Verzeichnis, in dem sich die entsprechende Datei befindet (bspw. /home/you/Dokumente)
.. (zwei Punkte) Verweisen auf ein Inhaltsverzeichnis, das sich eine Ebene höher befindet
. (ein Punkt) Verweist auf das aktuelle Inhaltsverzeichnis

Benennung von scripten

  • (lieber) kein Name, den es bereits als Kommando gibt. Einfach testen mit
    which script_name
  • Nur die Zeichen {A..Z}, {a..z}, {0..9} und _ . Sonderzeichen und [space] vermeiden.

Sonderzeichen in der Shell
;                       Befehls-Trennzeichen
&                       Hintergrund-Verarbeitung
( )                     Befehls-Gruppierung
|                       Pipe
< > &                   Umlenkungssymbole
* ? [ ] ~ + - @ !       Meta-Zeichen für Dateinamen
` ` (Backticks)         Befehls-Substitution 
$                       Variablen-Substitution
[newline] [space] [tab] Wort-Trennzeichen

Variablen

 a=hello     # einer Variablen "a" den Wert "hello" zuweisen
 echo $a     # die Variable "a" stdout ausgeben
 a=7         # der Variablen "a" einen neuen Wert zuweisen 
 b=8         # einer Variablen "b" den Wert "8" zuweisen
 c=$[a+b]    # einer Variablen "c" die Summe von a+b zuweisen 
 echo $c     # die Variable "c" an stdout ausgeben

vordefinierte Variablen ( Auszug ;-) )

*     Alle Aufrufparameter als ein String ("$*" == "$1 $2 $3 ...")
@     Alle Aufrufparameter als einzelne Strings ("$@" == "$1" "$2" "$3" ...)
#     Anzahl der Aufrufparameter	
?     Rückgabewert des letzten Kommandos	
$     Prozessnummer der aktiven Shell	
0     Name des aktuellen script
ERRNO    Fehlernummer des letzten fehlgeschlagenen Systemaufrufs	
PWD      Aktuelles Verzeichnis (wird durch cd gesetzt) 	
PATH     Suchpfade
USER     Benutzername

Beispiele

echo $PATH
echo $$

Mehr: http://wiki.bash-hackers.org/syntax/shellvars

Var. Zuweisung:

a=10

Var. Abruf:

echo $a

Programmstart

  • Programm startet durch Aufruf :
    ls
  • überall im Verz. Baum
  • Script muss executable gemacht werden
    chmod +x tolles_script.sh
  • Script startet durch Aufruf
    ./tolles-script.sh
Damit ein Script wie ein Programm startet:
  • Pfad d. Skriptes der $PATH Variable hinzufügen
  • export PATH=$PATH:/pfad/zum/script
  • muss in die .bashrc
  • Best Practice: Scripte in Ordner ~/bin/ -> diesen zur $PATH dazu

Gentlemen, open your Editor!

#!/bin/bash
clear
echo "Diese Infos werden von mysystem.sh bereitgestellt."
echo "Hallo, $USER"

echo "Heute ist der `date \"+%d.%m.%Y - %H:%M:%S\"`, dies ist Woche Nr. `date +"%V"`."
echo

echo "Diese Benutzer sind im Moment verbunden:"
w | cut -d " " -f 1 - | grep -v USER | sort -u
echo

echo "Dies ist `uname -s` und wir laufen auf einem $(uname -m) Prozessor."
echo

echo "Die uptime ist:"
uptime

MSG="\nDas ist alles! Bye, $USER! \n\n"
printf "${MSG}"

https://www.schubertdaniel.de/linuxkurs

https://git.scytec.de/danthefan/linuxkurs/raw/master/beispiele/mysystem.sh

echo "Hallo, $USER"
echo "Heute ist der `date \"+%d.%m.%Y - %H:%M:%S\"` "
w | cut -d " " -f 1 - | grep -v USER | sort -u
`uname -s`  vs  $(uname -s) 
MSG="\nDas ist alles! Bye, $USER! \n\n"
printf "${MSG}"

Ausführende Shell festlegen ( sog. She-Bang )

#!/bin/bash
#!/usr/bin/env ruby
#!/usr/bin/env python3
#!/usr/bin/php
Nötig, damit die shell weiss, wie das script interpretiert werden soll.
Script ohne she-bang:
bash mysql-backpup.sh
. mysql-backpup.sh
oder
php mysql-backpup.php
oder
ruby mysql-backpup.rb

Prozess in der bash - Erklärung:

neue Datei anlegen : finduser

#!/bin/bash
find / -user dany -print 2>/dev/null
Dann im Terminal ausführen
dany@laptop:~/bin$ chmod u+x finduser
dany@laptop:~/bin$ ./finduser 1>/dev/null &
dany@laptop:~/bin$ ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
dany      4987 23893  0 12:50 pts/4    00:00:00 /bin/bash ./finduser
dany      4988  4987 68 12:50 pts/4    00:00:01 find / -user dany -print
dany      5011 23893  0 12:50 pts/4    00:00:00 ps -f
dany     23893  4143  0 12:33 pts/4    00:00:00 bash
					

Die bash startet eine sub-shell, in der das Kommando ausgeführt wird

Der Kontext aller Script Variablen ist der der sub-shell

Ein weiteres Beispiel:
#!/bin/bash
suf=$1
if [ $# -gt 0 ]
  then
    for file in *.$suf; do
      bn=`basename "$file" .$suf | tr [:blank:]  _`
      new=$bn.$suf
      echo "neuer Dateiname:"
      echo $new
      mv "$file" $new
    done
  else
    echo "Verwendung: strip-space.sh SUFFIX"
    echo "Beende ...."
fi
Aufgabe: Erstellt ein script, das alle Dateien in eurem home in einer tar.gz - Datei archiviert, das Verzeichnis "~/archiv" erstellt, und die tar.gz Datei dorthin verschiebt.
Hinweis: tar -czf .....

https://linuxconfig.org/bash-scripting-tutorial

#!/bin/bash
tar -czf myhome_directory.tar.gz /home/$USER
mkdir archiv
mv myhome_directory.tar.gz archiv/

Kontrollstrukturen

if then

#!/bin/bash
cd 
ls
if [ -e sample.sh ] 
then 
 echo "file exists!" 
else 
 echo "file does not exist" 
fi

if then elif

#!/bin/bash
 cd
ls -l 
read -p "Enter a file name: " filename
if [ -e $filename ] 
then 
 echo "file exists!" 
 if [ -r $filename ]
 then 
      status="readable " 
 fi 
 if [ -w $filename ] 
 then 
      status=$status"writable " 
 fi 
 if [ -x $filename ] 
 then 
      status=$status"executable" 
 fi 
  echo "file permission: "$status 
else 
 echo "file does not exist" 
fi

for loop

#!/bin/bash
for f in {1..9}
do
	touch "$f xx.txt"
done

case

#!/bin/bash 
 clear 
 read -p "Integer1: " int1 
 read -p "Integer2: " int2 
 printf "Menu: \n[a] Addition\n[b]Subtraction\n[c]Multiplication\n[d]Division\n" 
 echo "======================" 
 read -p "Your choice: " choice 
 res=0 
 case $choice in 
	 a) 
	     res=$((int1+int2)) 
	 ;; 
	 b) 
	     res=$((int1-int2)) 
	 ;; 
	 c) 
	     res=$((int1*int2)) 
	 ;; 
	 d) 
	     res=$((int1/int2)) 
	 ;; 
	 *) 
	     echo "Invalid input" 
 esac 
 echo "The result is: " $res

while loop

#!/bin/bash
x=1
while [ $x -le 5 ]
do
  echo "Welcome $x times"
  x=$(( $x + 1 ))
done

until loop

#!/bin/bash
i=1
until [ $i -gt 6 ]
do
	echo "Welcome $i times."
	i=$(( i+1 ))
done

while vs until

  1. until läuft bis Bedingung nicht 0 (false)
  2. while läuft bis Bedingung 0 (true)
  3. until läuft mind. einmal