Appearance
Linux Console
Viele Linux-Systeme – insbes. Server und viele Embedded Systeme - laufen ohne grafisches Display (headless) und somit ohne graphische Oberfläche. Deshalb sowie als Vorbereitung für die Raspberry Pi Versuche befassen Sie sich in diesem Versuch mit der „Textconsole“ resp. „Kommandozeile“ sowie etwas „Shell Scripting“ ...
ASCII-Textdateien und Dateirechte
ASCII Zeichen und Editoren
Unter einer ASCII-Datei versteht man eine Textdatei, welche nur Zeichen und Steuerzeichen aus dem 7-Bit ASCII Zeichensatz verwendet, also keine Zeichen aus dem erweiterten Unicode oder sonstige binär codierten Formatierungsanweisungen. Im Speicher und in der Datei abgelegt werden ASCII-Zeichen immer byteweise, wobei das oberste 8. Bit jeweils 0 ist. Diese Zeichen entsprechen auch jenen UTF-8 Zeichen, welche mit 1 Byte codiert werden: UTF-8 hat ja eine Variable Zeichenlänge von 1 bis 4 Bytes und wenn das oberste Bit im ersten Byte 0 ist, handelt es sich um ein 1-Byte codiertes (ASCII-)Zeichen.
ASCII-Texteditoren gibt einerseits für die Textkonsolen, andererseits auch für die graphischen Oberfläche wie z.B. Programm gedit
z.B. für GNOME, kwrite für KDE, mousepad für Xfce oder Notepad.exe für Microsoft Windows etc.
Bringt eine graphische Oberfläche keinen eigenen ASCII-Editor mit, kann ein beliebiges der oben aufgeführten Linux Programme verwenden (excl. natürlich Notepad.exe). Ubuntu (mit der GNOME Oberfläche) installiert standardmässig gedit
.
ASCII-Editoren für die Textkonsole werden hingegen auf Systemen ohne Display resp. ohne graphische Oberfläche verwendet, wobei nano
relativ simpel und einfach bedienbar ist und auf vielen Linux-Systemen sowie auch auf OS-X standardmässig installiert wird. Daneben gibt es auch etliche Relikte aus der UNIX-Zeit wie z.B. vi
, vim
oder emacs
...
Erstellen Sie auf der Kommandozeile (also in einem „Terminal“) mit nano datei1
eine Datei namens datei1, speichern Sie diese und öffnen Sie diese wiederum mittels gedit
.
Sie können gedit sowohl von der Kommandozeile unter direkter Angabe der zu editierenden Datei starten oder von der graphischen Oberfläche. Auf letzterer ist gedit einfach als „Texteditor“ aufgeführt. Natürlich können Sie auch einfach eine bestehende Text-Datei im Dateimanager doppelclicken ...
Soll eine existierende ASCII-Textdatei auf Kommandozeilenebene bloss kurz angezeigt werden, so kann dies auch mittels cat
erfolgen:
bash
cat datei1
cat
'cat' schreibt wie die meisten Konsoleprogramme den „Output“ mittels C-Funktion printf()
auf die so genannte „Standard-Ausgabe“ , engl. „standard output“ oder kurz stdout
[1].
Wo stdout
hinführt (in unserem Fall ins „Terminal“ Window) wird vom übergeordneten Programm vererbt. In unserem Fall von der bash
Shell an das von dieser gestartete Programm cat
.
Zur Anzeige grösserer Text-Dateien ist cat
jedoch unpraktisch, da es gleich die gesamte Datei ausgibt.
Tauglicher hierfür ist das Programm less
. Betrachten Sie damit die Systemlog-Datei /var/log/syslog
.
Navigieren in less
Mittels der „Leerschlag“ Taste oder den PageUp/PageDown Tasten kann die Datei seitenweise durchgeblättert werden oder mit den up/down Pfeiltasten zeilenweise.
Beenden kann man less
per q
wie „quit“ und nicht wie die meisten anderen Konsole-Programme per Ctrl-C
.
Wenn Sie cat /etc/sudoers
eingeben, wird bloss eine Fehlermeldung ausgegeben, obwohl diese Datei im Ordern /etc
existiert - wie z.B. mit ls /etc/sudoers
überprüfen können.
Linux Permissions
Jedem Dateisystem-Objekt, also jeder Datei (engl. file) und jedem Ordner (engl. directory), ist einem „Eigentümer“ (engl. owner) und eine Sicherheits-Gruppe (engl. group) zugewiesen!
Sowohl für den owner einer Datei als auch für die aufgeführte group als auch „alle anderen“ (engl. others) sind Rechte in Form von „Rechte Flags“ (engl. permissions flags) definiert wie:
- Leserecht (
read
) Datei resp. Ordnerinhalt darf gelesen werden - Schreibrecht (
write
) Datei darf verändert werden, resp. Dateien in Ordern erzeugt/gelöscht - Ausführungsrecht (
execute
) Datei darf als Script ausgeführt werden, Ordner „betreten“ Die permissions einer Datei können mit der langen Ausgabe vonls
angezeigt werden, also per:ls -l
Die Ausgabe erfolgt dann in folgender Form:
<permissionflags> <ref> <owner> <group> <Grösse> <Änderungsdatum> <Dateiname>
wobei die <permissionflags>
folgende Bedeutung haben:
- Zeichen = Objektart:
-
normale Datei,d
directory (also Ordner),l
symbolischen Link
- Zeichen = Objektart:
- ab dem 2. Zeichen werden nacheinander jeweils
read
/write
/exeute
Rechte für den owner, die angegebene group sowie others aufgeführt, wobei "others" alle User ausser der aufgeführte owner und Mitglieder der aufgeführten group sind. Also 3 x 3 Zeichen.
Auf Ordnern (directories) ist sowohl Leserecht (read
) als auch Ausführungsrecht (execute
) nötig, damit betreffende Ordnerinhalt aufgelistet und der Ordner „betreten“ werden kann.
Gespeichert werden diese Datei-Metadaten übrigens im sogenannte inode
der jeweiligen Datei.
Frage: Wer hat also gem. ls -l /etc/sudoers
welche Rechte auf dieser Datei?
Frage: Wie können Sie diesen Dateiinhalt trotz fehlender read Permission mit cat
anzeigen?
- Dateien und Ordner welche mit einem Punkt beginnen sind standardmässig versteckt, werden also mit normalem
ls
oderls -l
nicht aufgeführt, können aber mit der ls Option-a
ebenfalls aufgelistet werden. Listen Sie auch den versteckten Inhalt Ihres Home Ordners auf... ls
kennt noch viele weitere Optionen, welche aber nur selten benötigt werden, vgl. Kurzhilfe per Aufruf von ls mittels Option--help
(alsols --help
) sowie die ausführliche Hilfeseiten perman ls
(Beenden mitq
).
Kommandozeile und Input-/Output Redirection
Geben Sie folgendes auf der Kommandozeile ein:
bash
echo hello world
das Programm echo
gibt bloss alle aufgeführten Kommandozeilenargumente auf stdout
aus.
Sonderzeichen
Viele Sonderzeichen haben auf der Kommandozeile spezielle Bedeutung, ein *
ist z.B. das „Wildcard“ Zeichen und trifft somit auf alle Dateien im aktiven Ordner zu. Soll Text auf der Kommandozeile als reiner Text, ohne derartige „Expansion“ angegeben werden, muss der Text in einfache senkrechte Anführungszeichen ('
) gesetzt werden (sogenannt „quoted“).
Betrachten Sie die folgende Ausgaben:
bash
echo So wird ein Stern * expandiert!
echo 'So wird ein Stern * nicht expandiert ?'
Anführungszeichen
Wie interpretiert die Shell die verschiedenen Anführungszeichen?
echo 'i am $USER'
: Text zwischen Einfach-Anführungszeichen (single quote) wird ohne Variablenexpansion ausgegeben.echo "i am $USER"
: Text zwischen Doppel-Anführungszeichen (double quote) wird mit Variablenexpansion ausgegeben.echo "my UID is `id -u`"
Text zwischen Rückwärts-Hochkomma (backtick) führt die Shell vorgängig als Programm aus ausgeführt und setzt das Ergebnis (resp. den "Standard Output" des aufgerufenen Programms) an der betreffenden Stelle ein!
Umleiten von Output
Per >
und >>
lässt sich der „Standard Output“ auch statt auf der Console in eine Datei umleiten:
bash
echo 'eine erste Zeile' > datei2
echo 'eine weitere Zeile anhängen' >> datei2
Beachten Sie, dass nur der Text in Anführungszeichen gesetzt werden darf und nicht die Umleitung!
> datei
: leitet den „Standard Output“ eines Programms in die angegebene Datei um. Existiert diese bereits, wird sie überschrieben.>> datei
: hängt den „Standard Output“ eines Programms an eine bestehende Datei an (engl. append)|
: program leitet den „Standard Output“ eines Programms auf den „Standard Input“ (stdin
) des angegebenen Programms. Normalerweise iststdin
die Tastatur.
Eine Datei kann also statt mit einem Texteditor wie nano
oder gedit
auch mit echo
und Standard-OutputRedirection erstellt werden. Diese Variante eignet sich v.a. für Shell-Scripts (s. später).
Mittels cat
in Kombination mit „Standard-Output-Redirection“ lassen sich folglich sogar Dateien kopieren:
bash
cat datei2 >datei3 kopiert datei3 auf datei4
Üblicherweise wird zum Kopieren natürlich das Kommando cp
verwendet:
bash
cp datei2 datei3
Der Standard Output (stdout
) eines Programmes lässt sich gemäss obiger Tabelle mittels |
auch auf den Standard Input (stdin
) eines anderen Programmes umleiten (engl. pipe
, also wie durch eine Röhre).
Das Programm dmesg
gibt den Kernel-Log seit dem Booten auf der Standard-Ausgabe aus. Alleinstehend ausgeführt ist die Ausgabe viele Bildschirmseiten lang (versuchen Sie's!).
Um die Ausgabe seitenweise auszugeben, kann wie folgt der Output von dmes
' gefolgt von |
in das Programm 'less' gepiped werden, denn less
ist ein so genanntes "Pager" Programm.
bash
dmesg | less # Tipp: Je nach System ist vor dmesg ein sudo nötig
Das Weiterblättern erfolgt bei less
wie erwähnt per Leerschlag, ein vorzeitige Abbruch per q
.
Wieviele Zeilen gibt der Command dmesg
aus? Auch dies lässt sich einfach ermitteln:
bash
dmesg | wc -l # wc steht übrigens für Word Count und -l für lines
Programmargumente
Viele Commands (wie cat
, less
, wc
, sort
, find
, grep
, tar
, ...) können sowohl mit als auch ohne DateiArgument aufgerufen werden: Erfolgt eine Dateiangabe hinter dem Programmnamen (also ein Commandline-Argument), wird der Inhalt dieser Datei als „Input“ verwendet, andernfalls erfolgt die Eingabe von stdin
, also per Tastatureingabe oder im falle von |
aus einer "Pipe" von einem anderen Programm.
Diese Philosophie stammt ursprünglich von UNIX: viele kleine Commands, welche jeweils nur eine Aufgabe gut erledigen und sich bei Bedarf mittels "piping" aneinanderreihen lassen...
Erinnern Sie sich an ps -ef | grep X
aus dem letzten Versuch? Nun verstehen Sie den Zusammenhang!
- Lassen Sie sich die Datei
/etc/passwd
percat
anzeigen ...
Versuchen Sie nun in einer einzigen Commandozeile mittels cat
die Passwortdatei /etc/passwd
auszulesen und dessen Output direkt auf das Programm cut
zu führen, wobei cut
durch Angabe geeigneter Optionen jeweils nur den Text vor dem ersten :
ausschneiden soll[2].
- Klappt dies, sortieren Sie zudem das Ergebnis mittels Programm
sort
(alles in einer einzigen Kommadozeile!)
Wildcards und Dateisuche
Das Wildcardzeichen *
kann nicht nur alleine stehend sondern auch in Kombination mit einem Dateinamen und/oder Dateipfad verwendet werden. Die Shell ersetzt also z.B. dat*
mit der Liste aller Dateien im aktuellen Ordner, auf welche das Muster passt, also z.B. auf datei1
, datei2
oder auch dat
oder datei.txt
.
Mit ls -l dat*
werden also genau jene Dateien detailliert angezeigt, welche mit dat
beginnen oder mit cat dat*
werden die betreffenden Dateiinhalte allesamt auf stdout
angezeigt.
Weiss man hingegen nicht, wo sich eine Datei im Dateisystem befindet, ist man mit find
gut bedient:
find <Startordner> <Optionen>
Im Dateisystem wird damit alles unter dem <Startordner>
gesucht. Nach was gesucht wird kann mittels Optionen angegeben werden: [3]
Um beispielsweise im gesamten Dateisystem nach allen Dateien zu suchen, in deren Dateiname dat
vorkommt, geben Sie z.B. folgendes ein:
bash
find / -name '*dat*'
# (Versuchen Sie's, Sie können mit Ctrl-C vorzeitig abbrechen falls es zu lange dauert…)
Frage: Im Beispiel oben ist das Suchmuster '*dat*'
in einfache Anführungszeichen gesetzt. Weshalb wohl?
Mit find
könnte man auch nach Datei-Attributen suchen, z.B. nach Dateien, welche älter oder nicht älter als so und soviele Tage alt sind oder Dateien mit einem bestimmten „owner“ oder Dateirecht etc. etc.
-
bei Programmoptionen
Allgemein ist bei den meisten UNIX-oiden Programmen üblich, dass die Programmoptionen (beginnend mit einem Minuszeichen) unmittelbar nach dem Command angegeben werden müssen.
Eine der wenigen Ausnahme ist das Programm find
, bei welchem die Optionen erst nach dem Dateipfad-Argument stehen!
Weiter unterscheidet man generell zwischen kurzen und langen Programmoptionen, wobei üblicherweise kurze Optionen mit nur einem Minuszeichen und einem Buchstaben sowie lange, ausführliche Optionen mit zwei Minuszeichen gefolgt von einem Wort angegeben werden.
Kurze Optionen lassen sich dann kombinieren wie z.B. ls -al
statt ls -a -l
.
Auch hier ist find
eine Ausnahme, denn die find
Optionen welche nach dem Dateipfad-Argument angegeben werden sind immer lange Optionen welche mit nur einem Minuszeichen angegeben werden.
find
durchsucht also immer die Metadaten der Dateien wogegen grep
nach Dateiinhalt sucht!
Dabei müssen die Kommandozeilenargumente bei grep
in folgender Reihenfolge angegeben werden:
grep [<Optionen>] <Suchtext> <ein oder mehrere Dateien>
Die eckigen Klammern werden dabei nicht eingegeben, sie bedeuten dass Optionen optional sind.
grep
gibt dabei nur jene Zeilen in Dateien aus, in welchen der betreffende Suchtext vorkommt. z.B. um in allen Dateien des aktiven Ordner nach dies
zu suchen ist folgende Eingabe nötig: grep dies *
Oft möchte man nicht nur einzelne Dateien durchsuchen sondern alle Dateien unter einem bestimmten Ordner inkl. Unterordner, was mittels grep Option -r
(wie „rekursiv“) machbar ist.
Frage: Suchen Sie in allen Dateien unter dem Ordner /etc
nach Ihrer User-Id. Wie verwenden Sie grep
?:
Für alle Dateien oder Ordner, welche mangels Leserecht nicht lesbar sind, wird ein Fehler ausgegeben.
Um dies zu verhindern, könnte natürlich grep mit vorangesetzem sudo aufzurufen werden, womit auch diese Dateien und Ordner durchsucht würden - oder alternativ durch anfügen von 2> /dev/null
wodurch der „Error Output“ (also alle Fehlermeldungen) ins „Nirvana“ beförtert werden.
2>
ist also die „Error Output Redirection“ und /dev/null
eine Pseudodatei, welche ins Nirvana läuft.
Umgebungsvariablen (Environment Variable)
Die für die laufende Shell gültigen Umgebungsvariablen lassen allesamt mittels env
anzeigen.
Oder bloss eine spezifische Umgebungsvariable per: echo $VARIABLENNAME
.
Expandieren
Aufgrund des $
-Zeichens vor einem beliebigen Wort (z.B. $VARIABELNNAME
) "expandiert" die laufende Shell die aufgeführte Umgebungsvariable, d.h. die Shell übergibt dem angegebenen Programm effektiv den Inhalt der Variable.
- Betrachten Sie mit beiden Varianten (
env
und mitecho
) den Inhalt der UmgebungsvariablePATH
.
Wichtige Besonderheit der PATH
Variable
Wird auf der Kommandozeile ein Programmname ohne eine davor gesetzte Pfadangabe angegeben, wie z.B. ls
und nicht /bin/ls
, durchsucht die Shell zwecks Auffinden des Programmes der Reihe nach alle Ordner, welche in der PATH
Umgebungsvariable enthalten sind.
Die Shell nutzt also einerseits einige Umgebungsvariablen selbst, andererseits werden die Umgebungsvariablen auch an die aufgerufenen Programme übergeben.
Weiter können auf Shell-Ebene auch Umgebungsvariablen überschrieben oder beliebig neue Umgebungsvariablen definiert werden.
Mit der Umgebungsvariable LANG
(oder manchmal auch LANGUAGE
[4]) wird z.B. die bevorzugte Ausgabe-Sprache und der Zeichensatz festgelegt, welche Programme verwenden sollen (sofern das aufgerufene Programm „multilingual“ ist und die entsprechende Sprache installiert ist).
Frage: Ermitteln und interpretieren Sie den Inhalt dieser Umgebungsvariable LANG
:
Falls Sie „Deutsch“ bei der Installation gewählt haben, werden folglich z.B. bei cat /etc/shadow
oder ls --help
deutsche (Fehler-)Meldungen ausgegeben.
Auf folgende Weise können die Umgebungsvariablen neu definiert oder überschrieben werden:
Zuweisung | Effekt |
---|---|
foo=bla | Definiert die Umgebungsvariable foo auf den Wert bla . |
foo='bla bla bla' | Falls Leerschläge im zu definierendem Text enthalten sind, muss der Text in einfache Anführungszeichen gesetzt werden. Bei Verwendung von Doppel-Anführungszeichen werden darin enthaltene Variablen oder Wildcards vor der Zuweisung „expandiert“. |
export foo=bla | Die Shell übergibt Umgebungsvariablen auch an neu gestartete Programme weiter, sofern die Variable „exportiert“ wird. Andernfalls kann die Variable nur von der Shell selbst verwendet werden. |
foo=bla xyz | Hier wird foo nur temporär definiert und dem (neu gestarteten) Programm xyz übergeben |
foo=`cmd` | Der Standard-Output des Programmes cmd wird der Variable foo zugewiesen |
Stolperfallen
foo= bla
: Hier wird aufgrund des Leerschlages hinter dem Gleichheitszeichen die Umgebungsvariablefoo
als leer definiert und versucht das Programmbla
zu starten!foo = bla
: Aufgrund des ersten Leerschlages zwischenfoo
und dem Gleichheitszeichen erfolgt gar keine Variablenzuweisung:foo
wird als Programm gestartet und diesem als erstes Argumente das Gleichheitszeichen und als zweites Argumentbla
übergeben!
Keine Leerschläge bei Zuweisungen
Bei der bash
gilt also die Faustregel: Niemals Leerschläge (resp. Whitespace) bei Zuweisungen!
Soll nach einer Programm-Fehlermeldung „gegoogelt“ werden, ist es oft treffender, wenn man englische Fehlermeldungen hat, was durch Übergabe einer leer definierten LANG
Umgebungsvariable möglich ist.
Frage:: cat /etc/shadow
liefert einen Fehler. Wie ermitteln Sie die englische Fehlermeldung?
Frage:: Verifizieren Sie die Vererbung einer mit export
definierten Umgebungsvariablen, indem Sie nach Definition einer neuen Umgebungsvariable eine Sub-Shell (per sh
oder bash
) starten und die Variable anzeigen.
Ist auch wirklich eine neue (Sub-)Shell aktiv? Kontrollieren Sie dies mittels ps -f
(ohne -e
!)[5]
Die Sub-Shell können Sie per exit
beenden, wodurch Sie wieder in der ursprünglichen Shell landen.
Umgebungsvariablen können nur jeweils „weitervererbt“ werden, sind also nicht „global“ !! Aber wo werden die vordefinierten Umgebungsvariablen gesetzt?
Beim Einloggen des Benutzers wird eine so genannte „Login-Shell“ gestartet und diese included die so genannten „Login-Scripts“: einerseits die Datei /etc/profile
, andererseits aus dem Home-Verzeichnis des Benutzers die versteckte Datei .profile
Alle weiteren vom Benutzer gestarteten Programme (inkl. graphische Oberfläche) werden direkt oder indirekt von dieser Login-Shell gestartet und erben somit die in diesen profile-Dateien definierten Umgebungsvariablen.[6]
Jobs
Wird ein Programm gestartet, erhält dieses für dessen Laufzeit die Standard-Eingabe (stdin
) von der Tastatur. Die Shell welche das Programm gestartet hat, ist solange von stdin
abgekoppelt und blockiert.
Commands können auch im Hintergrund (engl. background) gestartet werden, in welchem Fall das Programm keine Tastatur Standard-Eingabe (stdin
) erhält. Somit behält die Shell die Standard-Eingabe.
Sinnvoll ist dies nur, wenn keine Tastatur-Eingabe erforderlich ist, also z.B. für Programme wie gedit
welche die Ein-/Ausgabe über die graphischen Oberfläche also in einem eigenen Fenster vornehmen:
bash
gedit datei1 &
Ein vorangesetztes sudo
ist jedoch heikel, denn sudo
erwartet ja (meist) eine Passworteingabe und wartet demzufolge geduldig und hoffnungslos im Hintergrund auf diese Benutzereingabe!
Statt ein Programm direkt im Hintergrund (mittels &
) zu starten, kann ein Vordergrundprozess auch nachträglich in den Background befördert werden, wozu der Vordergrundprozess zuerst per Ctrl-Z
angehalten wird und darauf per Shell-Kommando bg
im Background wieder reaktiviert wird.
Umgekehrt kann per Kommando fg
ein sich im Hintergrund befindlicher Prozess wieder in den Vordergrund gebracht werden.
- Versuchen Sie beides anhand von
gedit
Einen im Vordergrund laufenden Prozess, lässt sich meist per Ctrl-C
beenden, wobei der betreffende Prozess hierzu bloss aufgefordert wird, d.h. sich dagegen auch wehren kann oder vor dem Beenden noch Aufräumarbeiten vornehmen kann.
Bei Hintergrund-Prozessen funktioniert Ctrl-C
natürlich nicht, da Hintergrundprozesse ja von der StandardEingabe (Tastatur) abgekoppelt sind und diese Tastenkombination folglich nur die Shell erreichen (glücklicherweise ignoriert die Shell Ctrl-C
). Versuchen Sie auch dies nach Aufruf von gedit
.
Alternativ zu Ctrl-C
lassen sich Prozesse aber auch per Kommando kill
oder killall
beenden. Bei ersterem muss die Prozess-ID (PID
) (gemäss ps
resp. ps -ef
) angegeben werden, bei killall
hingegen der Name des Programmes. Laufen mehrere gleichnamige Programme, werden mit letzterem alle beendet!
- Öffnen Sie mehrere „Terminal“ Fenster und geben Sie dann
killall gnome-terminal-server
ein….
Ein Prozess kann eine derartige Aufforderung auch ignorieren, was z.B. bei der bash Shell der Fall ist. Gegen ein „brutales“ SIGKILL
(Signal Nr. 9) kann sich aber kein Prozess wehren, denn damit wird der Prozess vom Betriebssytem (Linux-Kenel) sofort beendet, d.h. der Prozess wird nicht wie vorher „zum Beenden aufgefordert“.
Ein killall -SIGKILL bash
oder killall -9 bash
beendet also brutal alle bash
Shells welche mit der eigenen Benutzerid gestartet wurden!
SIGKILL
(resp. das Signal -9
) sollte man jedoch nur in Ausnahmefällen verwenden. Wie erwähnt können abgesehen vom User root (und ohne sudo-Recht) nur eigene Prozesse beenden
Standardmässig werden beim Beenden eines Prozesses auch dessen Child-Prozesse automatisch beendet – beim Beenden des „Terminal“ (z.B. per killall gnome-terminal-server
) werden folglich auch die Shell und in der Folge auch alle aus der Shell gestarteten Vordergrund- und Hintergrund-Prozesse beendet – wie z.B. ein zuvor aus der Shell gestarteter gedit
Prozess.
Shell Scripting
Ein „Shell Script“ ist eine Aneinanderreihung von Kommandozeilen in einer Textdatei, welche von einer Shell abgearbeitet werden kann. Bei Shell-Scripts ist wie bei normalen Programmen auch eine bedingte und/oder iterative Ausführung möglich.
Dienlich sind Shell-Scripts vorwiegend für einfache wiederkehrenden Aufgaben, wogegen für komplexe Vorgänge besser leistungsfähigere Scriptsprachen wie Python oder Perl oder gar compilierte Programme auf Basis C
oder Java
, etc. verwendet werden.
Shell
-, Perl
- und Python
- Scripts werden intensiv auch bei der Linux Systeminstallation oder auch beim Systemstart verwendet – oder auch beim Installieren von Programmpaketen verwendet (z.B. mittels apt install ...
) denn in diesem Fall wird zum Schluss des Installationsvorganges ein allenfalls im betreffenden Package vorhandenes „Post-Install-Script“ ausgeführt…
Script interpreter
Beim Starten eines Programmes oder einer Scriptdatei übergibt die Shell dem Linux-Kernel den Pfad zur betreffenden Datei. Der Kernel prüft darauf, ob die Datei gemäss dessen Dateirechte für den User ausführbar, also executable ist.
Folglich müssen Scripts welche direkt aufgerufen werden sollen, das Dateirecht execute gesetzt haben!
Ist dies der Fall, überprüft der Kernel den Beginn der Datei: falls es ein Binärprogramm (resp. eine ELFDatei) ist, startet er dieses. Eine Scriptdatei muss hingegen mit der so genannten „Shebang“ Zeichenfolge #!
beginnen, hinter welcher der Pfad zum gewünschten „Kommandointerpreter“ angegeben wird.
Im Falle eines Shell-Scripts ist also hinter der „Shebang“ Zeichenfolge der Pfad zur Shell angegeben, also: #!/bin/sh
Der Kernel startet nach erkennen einer Shebang-Zeile dann den angegebenen Kommandointerpreter (also z.B. eine neue Shell) und übergibt dieser den Pfad zum Scriptdatei als Argument.
Dank diesem Mechanismus sind nicht nur Shell-Scripts mit beliebigen Shells möglich, sondern auch andere beliebige Script-Sprachen – sofern der betreffende Kommandointerpreter auch installiert ist.
Also z.B. auch Perl-Scripts (#!/usr/bin/perl
), Phyton-Scripts (#!/usr/bin/phyton
), oder Bash-Shell-Scripts (#!/bin/bash
), etc. etc. , wobei die bash Shell ja bekanntlich eine erweiterte sh
POSIX-Shell ist.
Für den gestarteten Interpreter ist die „Shebang“ Zeile übrigens bloss Kommentar, denn das Hash-Zeichen #
ist bei allen aufgeführten Scriptsprachen immer das Zeichen für einen einzeiligen „Kommentar“.
- Erstellen Sie folgendes Shell-Script namens
myscript1
sh
#! /bin/sh
DIRS=`echo $PATH | tr ':' ' ' `
for dir in $DIRS ; do
echo "Im Programmordner $dir sind `ls $dir | wc -l` Dateien"
done
echo insgesamt also `ls $DIRS | wc -l` Dateien.
Die erste Zeile ist die „Shebang“ Zeile.
Auf der Scriptdatei muss das „executable“ Flag gesetzt werden was mit
chmod +x <scriptname>
möglich ist.$PATH
ist bekanntlich eine durch Doppelpunkte getrennte Liste. Damit über diese Liste iteriert werden kann, müssen zuerst die Doppelpunkte durch Leerschläge ersetzt werden, was mittels Programmestr
(wie translate) mit den Argumenten Suchzeichen und Ersatzzeichen machbar ist.Die
for
-Schleife wird über die in der Umgebungsvariable folders gespeicherten Ordnerliste iteriertUm die Anzahl Einträge in einem Dateiordner zu zählen, wird der Output von
ls Ordnerpfad
in den Standard-Input vonwc -l
geleitet.wc
steht für word count, die Option-l
für lines.Unter Verwendung von
echo
wird dann der Pfad sowie das Ergebnis der Zählung ausgegeben.Die Scriptdatei kann durch Eingabe von
myscript1
nicht gestartet werden, denn die Shell sucht ja nur in den Ordnern, welche in der UmgebungsvarialblePATH
aufgeführt sind nach ausführbaren Programmen und Scripts. Vor die Datei muss also der Pfad zum aktuellen Ordern gesetzt werden...Führen Sie die Datei deshalb mittels
./myscript1
aus (Achtung: keine Leerschläge nach.
und/
)Stellen Sie eine Diskrepanz der Werte zur Gesamtsumme fest? Wenn ja, listen Sie mit
ls -l /
den RootOrdner auf (also den obersten Ordner im Verzeichnisbaum) und überlegen Sie, weshalb das so ist!
Wenn dies klappte, kopieren Sie myscript1
auf myscript2
und erweitern letzteres folgendermassen:
Mittels Programm file
und einem oder mehreren Datei-Argumenten kann der Inhalt einer Datei ermittelt werden: Das Programm file
versucht den Typ des Dateiinhaltes zu ermitteln, also ob es sich um eine Textdatei, ein Binärprogramm etc. oder (anhand der „Shebang“ Zeile) um eine Scriptdatei handelt.
- Experimentieren Sie zuerst etwas mit dem Programm 'file'
- Klappt auch dies, soll nun bei jedem Iterationsdurchlauf (d.h. in jedem Programmordner) die Anzahl Shell-, Python- sowie Perl-Scripts separat gezählt und angezeigt werden.[7]
Commandline Argumente an ein Script übergeben
Wird ein Script mit Argumenten aufgerufen, z.B. ./myscript aaa bbb ccc
, sind diese Argumente innerhalb des Scripts mit $1 $2 $3
zugreifbar. $*
wären alle Argumente und $0
ist der Aufruf selbst…
- Versuchen Sie's!
Fehlerjournal
Wenn das System nicht so funktioniert wie es sollte, kann ein Blick in das Fehlerjournal nützlich sein. Unsere Ubunt-Distributionen verwenden das Init-System systemd
, bei welchem das Fehlerjournal mittels Command journalctl
betrachtet werden kann. Versuchen Sie's (Bedienung und Abbruch wie bei less
).
Oft will man nur das Ende des Fehlerjournals betrachten, was mit journalctl -e
einfach machbar ist.
Sie kennen
printf()
vermutlich ja aus demmcGl
-Unterricht, es ist eine Funktion der „C Standard Library“. ↩︎Tipp: Kurzhilfe von
cut
percut --help
oder ausführlicher perman cut
. ↩︎Normalerweise folgen Optionen vor den "normalen" Programmargumenten.
find
hat diesbezüglich eine unübliche Syntax, denn die Optionen sind erst am Schluss aufgeführt, also erst nach Angabe des<Startordners>
. ↩︎https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html#Locale-Environment-Variables ↩︎
Tipp: Achten Sie sich sowohl auf die Process-ID als auch auf die Prozess-Parent ID (PID) ↩︎
Die bash-Shell liest übrigens noch weitere Profildateien ein, vgl.
man bash
fast zuunterst unterFILES
... ↩︎Tipp: Den Standard Output von
file ordnerpfad/*
mittelsgrep suchkriterium
filtern und danach mittelswc -l
zählen und ausgeben… ↩︎