105.2 Lektion 2
Zertifikat: |
LPIC-1 |
---|---|
Version: |
5.0 |
Thema: |
105 Shells und Shell-Skripte |
Lernziel: |
105.2 Einfache Skripte anpassen oder schreiben |
Lektion: |
2 von 2 |
Einführung
Shellskripte sind im Allgemeinen dazu gedacht, Vorgänge im Zusammenhang mit Dateien und Verzeichnissen zu automatisieren, also dieselben Vorgänge, die Sie auch manuell an der Kommandozeile ausführen könnten. Die Reichweite von Shellskripten ist jedoch nicht auf die Dokumente eines Benutzers beschränkt, denn Konfiguration und Interaktion mit vielen Aspekten eines Linux-Systems erfolgen über Skriptdateien.
Die Bash bietet viele eingebaute Befehle zum Schreiben von Shellskripten, aber die volle Leistungsfähigkeit dieser Skripte entfaltet sich erst in deren Kombination mit den vielen auf der Kommandozeile eines Linux-System verfügbaren Dienstprogrammen.
Erweiterte Tests
Bash als Skriptsprache ist hauptsächlich auf die Arbeit mit Dateien ausgerichtet, daher verfügt der in der Bash eingebaute Befehl test
über viele Optionen zur Auswertung der Eigenschaften von Dateisystemobjekten (v.a. Dateien und Verzeichnisse). Tests für Dateien und Verzeichnisse prüfen beispielsweise, ob die Dateien und Verzeichnisse, die für eine bestimmte Aufgabe benötigt werden, vorhanden und lesbar sind. Ist der Test erfolgreich, werden die entsprechenden Aktionen über eine if-Anweisung ausgeführt.
Der Befehl test
kennt zwei Syntaxformen zur Auswertung von Testausdrücken: als Argument für den Befehl test
oder in eckigen Klammern, wobei der Befehl test
implizit genutzt wird. Den Test, ob /etc
ein gültiges Verzeichnis ist, schreiben Sie also auf eine der folgenden Arten:
$ test -d /etc $ echo $? 0 $ [ -d /etc ] $ echo $? 0
Wie durch die Exit-Statuscodes in der speziellen Variable $?
bestätigt – der Wert 0
bedeutet, dass der Test erfolgreich war –, haben beide Formen /etc
als gültiges Verzeichnis ausgewertet. Unter der Annahme, dass der Pfad zu einer Datei oder einem Verzeichnis in der Variablen $VAR
gespeichert wurde, können Sie die folgenden Ausdrücke als Argumente für test
oder innerhalb eckiger Klammern verwenden:
-a "$VAR"
-
Prüft, ob der Pfad in
VAR
im Dateisystem existiert und ob es sich um eine Datei handelt. -b "$VAR"
-
Prüft, ob der Pfad in
VAR
eine blockorientierte Gerätedatei ist. -c "$VAR"
-
Prüft, ob der Pfad in
VAR
eine zeichenorientierte Gerätedatei ist. -d "$VAR"
-
Prüft, ob der Pfad in
VAR
ein Verzeichnis ist. -e "$VAR"
-
Prüft, ob der Pfad in
VAR
im Dateisystem existiert. -f "$VAR"
-
Prüft, ob der Pfad in
VAR
existiert und ob es sich um eine reguläre Datei handelt. -g "$VAR"
-
Prüft, ob der Pfad in
VAR
die SGID-Berechtigung hat. -h "$VAR"
-
Prüft, ob der Pfad in
VAR
ein symbolischer Link ist. -L "$VAR"
-
Prüft, ob der Pfad in
VAR
ein symbolischer Link ist (wie-h
). -k "$VAR"
-
Prüft, ob der Pfad in
VAR
die Berechtigung Sticky Bit hat. -p "$VAR"
-
Prüft, ob der Pfad in
VAR
eine Pipe-Datei ist. -r "$VAR"
-
Prüft, ob der Pfad in
VAR
für den aktuellen Benutzer lesbar ist. -s "$VAR"
-
Prüft, ob der Pfad in
VAR
existiert und nicht leer ist. -S "$VAR"
-
Prüft, ob der Pfad in
VAR
eine Socket-Datei ist. -t "$VAR"
-
Prüft, ob der Pfad in
VAR
in einem Terminal geöffnet ist. -u "$VAR"
-
Prüft, ob der Pfad in
VAR
die Berechtigung SUID gesetzt hat. -w "$VAR"
-
Prüft, ob der Pfad in
VAR
für den aktuellen Benutzer schreibbar ist. -x "$VAR"
-
Prüft, ob der Pfad in
VAR
für den aktuellen Benutzer ausführbar ist. -O "$VAR"
-
Prüft, ob der Pfad in
VAR
dem aktuellen Benutzer gehört. -G "$VAR"
-
Prüft, ob der Pfad in
VAR
zur betreffenden Gruppe des aktuellen Benutzers gehört. -N "$VAR"
-
Prüft, ob der Pfad in
VAR
seit dem letzten Zugriff geändert wurde. "$VAR1" -nt "$VAR2"
-
Prüft, ob der Pfad in
VAR1
neuer ist als der Pfad inVAR2
, entsprechend ihrer Änderungszeitpunkte. "$VAR1" -ot "$VAR2"
-
Prüft, ob der Pfad in
VAR1
älter ist alsVAR2
. "$VAR1" -ef "$VAR2"
-
Dieser Ausdruck wird als wahr gewertet, wenn der Pfad in
VAR1
ein Hardlink zuVAR2
ist.
Es empfiehlt sich, eine getestete Variable in Anführungszeichen zu setzen, da eine leere Variable einen Syntaxfehler für den Befehl test
verursachen könnte. Die Testoptionen erfordern ein Operanden-Argument, und eine leere Variable ohne Anführungszeichen würde einen Fehler aufgrund eines fehlenden erforderlichen Arguments verursachen. Es gibt auch Tests für beliebige Textvariablen:
-z "$TXT"
-
Prüft, ob die Variable
TXT
leer ist (Größe Null). -n "$TXT"
odertest "$TXT"
-
Prüft, ob die Variable
TXT
nicht leer ist. "$TXT1" = "$TXT2"
oder"$TXT1" == "$TXT2"
-
Prüft, ob
TXT1
undTXT2
gleich sind. "$TXT1" != "$TXT2"
-
Prüft, ob
TXT1
undTXT2
ungleich sind. "$TXT1" < "$TXT2"
-
Prüft, ob
TXT1
vorTXT2
kommt, in alphabetischer Reihenfolge. "$TXT1" > "$TXT2"
-
Prüft, ob
TXT1
nachTXT2
kommt, in alphabetischer Reihenfolge.
Unterschiedliche Sprachen können unterschiedliche Regeln für die alphabetische Reihenfolge haben. Für konsistente Ergebnisse, unabhängig von den Lokalisierungseinstellungen des Systems, auf dem das Skript ausgeführt wird, sollten Sie die Umgebungsvariable LANG
auf C
setzen (LANG=C
), bevor Operationen durchgeführt werden, die eine alphabetische Sortierung umfassen. Diese Definition behält auch die Systemmeldungen in der Originalsprache bei, daher sollte sie nur innerhalb des Geltungsbereichs des Skripts genutzt werden.
Numerische Vergleiche haben ihren eigenen Satz an Testmöglichkeiten:
$NUM1 -lt $NUM2
-
Prüft, ob
NUM1
kleiner ist alsNUM2
. $NUM1 -gt $NUM2
-
Prüft, ob
NUM1
größer ist alsNUM2
. $NUM1 -le $NUM2
-
Prüft, ob
NUM1
kleiner oder gleichNUM2
ist. $NUM1 -ge $NUM2
-
Prüft, ob
NUM1
größer oder gleichNUM2
ist. $NUM1 -eq $NUM2
-
Prüft, ob
NUM1
gleichNUM2
ist. $NUM1 -ne $NUM2
-
Prüft, ob
NUM1
ungleichNUM2
ist.
Alle Tests können die folgenden Modifikatoren erhalten:
! EXPR
-
Prüft, ob der Ausdruck
EXPR
falsch ist. EXPR1 -a EXPR2
-
Prüft, ob sowohl
EXPR1
als auchEXPR2
wahr sind. EXPR1 -o EXPR2
-
Prüft, ob mindestens einer der beiden Ausdrücke wahr ist.
Ein weiteres bedingtes Konstrukt, case
, ist eine Art Variante des if-Konstrukts. Die Anweisung case
führt eine Liste von Befehlen aus, wenn ein angegebenes Element — zum Beispiel der Inhalt einer Variablen — in einer Liste von Elementen enthalten ist, die durch Pipes (den vertikalen Strich |
) getrennt und durch )
abgeschlossen sind. Das folgende Beispielskript zeigt, wie Sie case
nutzen, um das Softwarepaketierungsformat für eine bestimmte Linux-Distribution anzuzeigen:
#!/bin/bash DISTRO=$1 echo -n "Distribution $DISTRO uses " case "$DISTRO" in debian | ubuntu | mint) echo -n "the DEB" ;; centos | fedora | opensuse ) echo -n "the RPM" ;; *) echo -n "an unknown" ;; esac echo " package format."
Sie müssen jede Liste von Mustern und zugehörigen Befehlen mit ;;
, ;&
, oder ;;&
abschließen. Das letzte Muster, ein Sternchen, passt, wenn keines der vorherigen Muster dem Suchbegriff entspricht. Die Anweisung esac
(case rückwärts) beendet das case
-Konstrukt. Angenommen das vorangegangene Beispielskript heißt script.sh
und wird mit opensuse
als erstem Argument aufgerufen, so erzeugt es die folgende Ausgabe:
$ ./script.sh opensuse Distribution opensuse uses the RPM package format.
Tip
|
Bash kennt die Option |
Das gesuchte Element und die Muster werden einer Tildeerweiterung, Parametererweiterung, Befehlssubstitution und arithmetischen Erweiterung unterzogen. Wenn das gesuchte Element mit Anführungszeichen angegeben ist, werden diese entfernt, bevor der Abgleich erfolgt.
Schleifenkonstrukte
Skripte sind oft Werkzeuge zur Automatisierung sich wiederholender Aufgaben, wobei die gleiche Reihe von Befehlen ausgeführt wird, bis ein Stoppkriterium greift. Die Bash verfügt über drei Schleifenanweisungen – for
, until
und while
–, die für verschiedene Schleifenkonstruktionen ausgelegt sind.
Das for
-Konstrukt durchläuft eine gegebene Liste von Elementen — normalerweise eine Liste von Wörtern oder anderen, durch Leerzeichen getrennten Textsegmenten — und führt für jedes dieser Elemente denselben Befehlssatz aus. Vor jeder Iteration weist die for
-Anweisung das aktuelle Element einer Variablen zu, die die Befehle dann nutzen können. Der Vorgang wird so lange wiederholt, bis keine Elemente mehr übrig sind. Die Syntax des for
-Konstrukts lautet:
for VARNAME in LIST do COMMANDS done
VARNAME
ist ein beliebiger Shellvariablenname und LIST
eine beliebige Folge getrennter Begriffe. Die gültigen Begrenzungszeichen, die Elemente in der Liste trennen, werden durch die Umgebungsvariable IFS
definiert; standardmäßig sind dies die Zeichen Space, Tab und Newline. Die Liste der auszuführenden Befehle steht zwischen den Anweisungen do
und done
, so dass Befehle so viele Zeilen wie nötig belegen können.
Im folgenden Beispiel nimmt der Befehl for
jedes Element aus der angegebenen Liste — eine Folge von Zahlen — und weist es der Variablen NUM
zu, ein Element nach dem anderen:
#!/bin/bash for NUM in 1 1 2 3 5 8 13 do echo -n "$NUM is " if [ $(( $NUM % 2 )) -ne 0 ] then echo "odd." else echo "even." fi done
Darüber hinaus enthält das Beispiel ein verschachteltes if
-Konstrukt in Verbindung mit einem arithmetischen Ausdruck, um auszuwerten, ob die Zahl in der aktuellen Variable NUM
gerade oder ungerade ist. Haben wir dieses Beispielskript script.sh
genannt und es befindet sich im aktuellen Verzeichnis, so liefert es die folgende Ausgabe:
$ ./script.sh 1 is odd. 1 is odd. 2 is even. 3 is odd. 5 is odd. 8 is even. 13 is odd.
Die Bash unterstützt auch ein alternatives Format für for
-Konstrukte, nämlich die Notation mit doppelten Klammern. Die Syntax ähnelt der for
-Anweisung aus der Programmiersprache C und ist besonders nützlich bei der Arbeit mit Arrays:
#!/bin/bash SEQ=( 1 1 2 3 5 8 13 ) for (( IDX = 0; IDX < ${#SEQ[*]}; IDX++ )) do echo -n "${SEQ[$IDX]} is " if [ $(( ${SEQ[$IDX]} % 2 )) -ne 0 ] then echo "odd." else echo "even." fi done
Dieses Beispielskript erzeugt dieselbe Ausgabe wie das vorangegangene. Statt jedoch in der Variable NUM
jeweils ein Element zu speichern, nutzt es die Variable IDX
, um den aktuellen Array-Index in aufsteigender Reihenfolge zu verfolgen — beginnend bei 0 und fortlaufend hinzfügend, solange er unter der Anzahl der Elemente im Array SEQ
liegt. Das aktuelle Element wird über seine Array-Position mit ${SEQ[$IDX]}
abgerufen.
Auf die gleiche Weise führt das until
-Konstrukt eine Befehlssequenz aus, bis ein Testbefehl — wie der Befehl test
selbst — mit Status 0
(Erfolg) endet. Die Schleifenstruktur aus dem vorherigen Beispiel können wir daher mit until
wie folgt implementieren:
#!/bin/bash SEQ=( 1 1 2 3 5 8 13 ) IDX=0 until [ $IDX -eq ${#SEQ[*]} ] do echo -n "${SEQ[$IDX]} is " if [ $(( ${SEQ[$IDX]} % 2 )) -ne 0 ] then echo "odd." else echo "even." fi IDX=$(( $IDX + 1 )) done
until
-Konstrukte benötigen zwar mehr Anweisungen als for
-Konstrukte, sind aber besser geeignet für nicht numerische Stoppkriterien, die Ausdrücke von test
oder andere Befehle bereitstellen. Es ist wichtig, Aktionen einzubinden, die ein gültiges Stoppkriterium sicherstellen, wie z.B. das Inkrement einer Zählervariablen, da andernfalls eine Schleife unendlich laufen kann.
Die Anweisung while
ist ähnlich der Anweisung until
, aber while
wiederholt die Befehlsreihe weiter, wenn der Testbefehl mit Status 0
(Erfolg) endet. Daher ist die Anweisung until [ $IDX -eq ${#SEQ[*]} ]
aus dem vorherigen Beispiel äquivalent zu while [ $IDX -lt ${#SEQ[*]} ]
, da die Schleife wiederholt werden soll, solange der Array-Index kleiner als die Summe der Elemente im Array ist.
Ein ausführlicheres Beispiel
Nehmen wir an, ein Benutzer möchte regelmäßig eine Sammlung seiner Dateien und Verzeichnisse mit einem anderen Speichergerät synchronisieren, das an einem beliebigen Einhängepunkt im Dateisystem eingehängt ist — ein eigenes Backup-System soll aber nicht eingesetzt werden. Da es sich um eine regelmäßig durchzuführende Aktion handelt, bietet sich die Automatisierung mit einem Shellskript an.
Die Aufgabe ist einfach: Synchronisieren Sie jede Datei und jedes Verzeichnis von einem als erstes Argument des Skripts angegebenen Ursprungsverzeichnis zu einem als zweites Argument angegebenen Zielverzeichnis. Um das Hinzufügen oder Entfernen von Einträgen in der Liste zu erleichtern, liegt diese in einer separaten Datei namens ~/.sync.list
mit einem Eintrag pro Zeile:
$ cat ~/.sync.list Documents To do Work Family Album .config .ssh .bash_profile .vimrc
Die Datei enthält eine Mischung aus Dateien und Verzeichnissen, einige mit Leerzeichen im Namen. Dies ist ein geeignetes Szenario für den eingebauten Bash-Befehl mapfile
, der jeden gegebenen Textinhalt analysiert und daraus eine Array-Variable erstellt, wobei jede Zeile als einzelnes Array-Element platziert wird. Die Skriptdatei nennen wir sync.sh
, und sie sieht wie folgt aus:
#!/bin/bash set -ef # List of items to sync FILE=~/.sync.list # Origin directory FROM=$1 # Destination directory TO=$2 # Check if both directories are valid if [ ! -d "$FROM" -o ! -d "$TO" ] then echo Usage: echo "$0 <SOURCEDIR> <DESTDIR>" exit 1 fi # Create array from file mapfile -t LIST < $FILE # Sync items for (( IDX = 0; IDX < ${#LIST[*]}; IDX++ )) do echo -e "$FROM/${LIST[$IDX]} \u2192 $TO/${LIST[$IDX]}"; rsync -qa --delete "$FROM/${LIST[$IDX]}" "$TO"; done
Die erste Aktion, die das Skript ausführt, ist die Definition von zwei Shellparametern mit dem Befehl set
: Die Option -e
beendet die Ausführung, sobald ein Befehl mit einem Status ungleich Null beendet wird, und die Option -f
deaktiviert das Globbing von Dateinamen. Beide Optionen kürzen wir mit -ef
ab. Dieser Schritt ist nicht zwingend, verringert aber die Wahrscheinlichkeit unerwarteten Verhaltens.
Bei den Anweisungen zur eigentlichen Anwendung der Skriptdatei können wir drei Teile unterscheiden:
-
Skriptparameter sammeln und prüfen
Die Variable
FILE
ist der Pfad zu der Datei mit der Liste der zu kopierenden Elemente:~/.sync.list
. Die VariablenFROM
undTO
sind der Ursprungs- bzw. Zielpfad. Da die letzten beiden Parameter vom Benutzer angegeben werden, durchlaufen sie einen einfachen Validierungstest, den dasif
-Konstrukt durchführt: Wenn einer der beiden kein gültiges Verzeichnis ist — geprüft durch[ ! -d "$FROM" -o ! -d "$TO" ]
— zeigt das Skript eine kurze Hilfemeldung und beendet sich dann mit einem Exit-Status1
. -
Laden der Liste der Dateien und Verzeichnisse
Sind alle Parameter definiert, erstellt der Befehl
mapfile -t LIST < $FILE
ein Array mit der Liste der zu kopierenden Elemente. Die Option-t
vonmapfile
entfernt das abschließende Zeilenumbruchzeichen aus jeder Zeile, bevor sie in die Array-VariableLIST
aufgenommen wird. Der Inhalt der durch die VariableFILE
angegebenen Datei —~/.sync.list
— wird über die Eingabeumleitung gelesen. -
Kopiervorgang durchführen und Benutzer informieren
Eine
for
-Schleife mit doppelter Klammerschreibweise durchläuft das Array der Elemente, wobei die VariableIDX
die Index-Erhöhung festhält. Der Befehlecho
informiert den Benutzer über jedes Element, das kopiert wird. Das escapete Unicodezeichen\u2192
für das Pfeil-nach-rechts-Zeichen steht in der Ausgabemeldung, weshalb die Option-e
des Befehlsecho
gesetzt werden muss. Der Befehlrsync
kopiert selektiv nur geänderte Dateien von der Quelle, weshalb er sich hier anbietet. Diersync
-Optionen-q
und-a
, zusammengefasst in-qa
, verhindern Meldungen vonrsync
und aktivieren den Archivmodus, in dem alle Dateieigenschaften erhalten bleiben. Die Option--delete
bewirkt, dassrsync
ein Element im Ziel löscht, das in der Quelle nicht mehr existiert — nutzen Sie diese Option daher mit Vorsicht.
Sofern alle Elemente in der Liste im Homeverzeichnis des Benutzers carol
(/home/carol
) vorhanden sind und das Zielverzeichnis /media/carol/backup
auf ein eingehängtes externes Speichergerät zeigt, erzeugt der Befehl sync.sh /home/carol /media/carol/backup
die folgende Ausgabe:
$ sync.sh /home/carol /media/carol/backup /home/carol/Documents → /media/carol/backup/Documents /home/carol/"To do" → /media/carol/backup/"To do" /home/carol/Work → /media/carol/backup/Work /home/carol/"Family Album" → /media/carol/backup/"Family Album" /home/carol/.config → /media/carol/backup/.config /home/carol/.ssh → /media/carol/backup/.ssh /home/carol/.bash_profile → /media/carol/backup/.bash_profile /home/carol/.vimrc → /media/carol/backup/.vimrc
Das Beispiel geht davon aus, dass das Skript von root oder vom Benutzer carol
ausgeführt wird, da die meisten Dateien für andere Benutzer nicht lesbar wären. Befindet sich script.sh
nicht in einem der Verzeichnisse, die in der Umgebungsvariablen PATH
aufgeführt sind, sollte es mit seinem vollständigen Pfad aufgerufen werden.
Geführte Übungen
-
Wie setzen Sie den Befehl
test
ein, um zu überprüfen, ob der in der VariablenFROM
gespeicherte Dateipfad neuer ist als eine Datei, deren Pfad in der VariablenTO
gespeichert ist? -
Das folgende Skript soll eine Zahlenfolge von 0 bis 9 ausgeben, liefert stattdessen aber unendlich oft
0
aus. Was müssen Sie ändern, um die erwartete Ausgabe zu erhalten?#!/bin/bash COUNTER=0 while [ $COUNTER -lt 10 ] do echo $COUNTER done
-
Ein Benutzer hat ein Skript geschrieben, das eine sortierte Liste von Benutzernamen benötigt. Die resultierende sortierte Liste erscheint wie folgt:
carol Dave emma Frank Grace henry
Auf dem Rechner eines Kollegen ist die gleiche Liste jedoch wie folgt sortiert:
Dave Frank Grace carol emma henry
Wie sind die Unterschiede zwischen den beiden sortierten Listen zu erklären?
Offene Übungen
-
Wie könnten Sie alle Befehlszeilenargumente des Skripts nutzen, um ein Bash-Array zu initialisieren?
-
Warum wird der Befehl
test 1 > 2
entgegen allen Erwartungen als wahr gewertet? -
Wie würden Sie das Standardfeldtrennzeichen vorübergehend nur auf das Zeilenumbruchzeichen ändern, so dass Sie es immer noch auf seinen ursprünglichen Inhalt zurücksetzen könnten?
Zusammenfassung
Diese Lektion beschreibt die für den Befehl test
verfügbaren Tests und andere bedingte Schleifenkonstrukte, die zum Schreiben komplexerer Shellskripte erforderlich sind. Als Beispiel für eine praktische Shellskriptanwendung dient ein einfaches Dateisynchronisationsskript. Die Lektion behandelt folgende Schritte:
-
Erweiterte Tests für die
if
- undcase
-Bedingungskonstrukte. -
Shellschleifenkonstrukte:
for
,until
undwhile
. -
Iterieren durch Arrays und Parameter.
Die angesprochenen Befehle und Prozeduren sind:
test
-
Führt einen Vergleich zwischen den an den Befehl übergebenen Elementen durch.
if
-
Logisches Konstrukt, das in Skripten verwendet wird, um etwas als entweder wahr oder falsch zu bewerten und dann die Befehlsausführung basierend auf den Ergebnissen zu verzweigen.
case
-
Wertet mehrere Werte gegen eine einzelne Variable aus. Die Ausführung des Skriptbefehls erfolgt dann in Abhängigkeit vom Ergebnis des Befehls
case
. for
-
Wiederholt die Ausführung eines Befehls auf der Grundlage eines bestimmten Kriteriums.
until
-
Wiederholt die Ausführung eines Befehls, bis ein Ausdruck als falsch gewertet wird.
while
-
Wiederholt die Ausführung eines Befehls, solange der gegebene Ausdruck als wahr gewertet wird.
Lösungen zu den geführten Übungen
-
Wie setzen Sie den Befehl
test
ein, um zu überprüfen, ob der in der VariablenFROM
gespeicherte Dateipfad neuer ist als eine Datei, deren Pfad in der VariablenTO
gespeichert ist?Der Befehl
test "$FROM" -nt "$TO"
gibt einen Statuscode0
zurück, wenn die Datei in der VariablenFROM
neuer ist als die Datei in der VariablenTO
. -
Das folgende Skript soll eine Zahlenfolge von 0 bis 9 ausgeben, liefert stattdessen aber unendlich oft
0
aus. Was müssen Sie ändern, um die erwartete Ausgabe zu erhalten?#!/bin/bash COUNTER=0 while [ $COUNTER -lt 10 ] do echo $COUNTER done
Die Variable
COUNTER
sollte inkrementiert werden, was mit dem arithmetischen AusdruckCOUNTER=$$COUNTER + 1
geschehen könnte, um schließlich das Stoppkriterium zu erreichen und die Schleife zu beenden. -
Ein Benutzer hat ein Skript geschrieben, das eine sortierte Liste von Benutzernamen benötigt. Die resultierende sortierte Liste erscheint wie folgt:
carol Dave emma Frank Grace henry
Auf dem Rechner eines Kollegen ist die gleiche Liste jedoch wie folgt sortiert:
Dave Frank Grace carol emma henry
Wie sind die Unterschiede zwischen den beiden sortierten Listen zu erklären?
Die Sortierung basiert auf dem aktuellen Locale (Gebietsschemaparameter) des Systems. Um Inkonsistenzen zu vermeiden, setzen Sie die Sortierung mit der Umgebungsvariablen
LANG
aufC
.
Lösungen zu den offenen Übungen
-
Wie könnten Sie alle Befehlszeilenargumente des Skripts nutzen, um ein Bash-Array zu initialisieren?
Die Befehle
PARAMS=( $* )
oderPARAMS=( "$@" )
erzeugen ein Array namensPARAMS
mit allen Argumenten. -
Warum wird der Befehl
test 1 > 2
entgegen allen Erwartungen als wahr gewertet?Der Operator
>
ist für String-Tests vorgesehen, nicht für numerische Tests. -
Wie würden Sie das Standardfeldtrennzeichen vorübergehend nur auf das Zeilenumbruchzeichen ändern, so dass Sie es immer noch auf seinen ursprünglichen Inhalt zurücksetzen könnten?
Sie können eine Kopie der Variablen
IFS
in einer anderen Variablen speichern:OLDIFS=$IFS
. Dann definieren Sie den neuen Zeilentrenner mitIFS=$'\n'
und setzen die Variable IFS mitIFS=$OLDIFS
wieder zurück.