Kategorie:Bash/Expansionen

Aus Foxwiki
Version vom 10. Dezember 2021, 23:06 Uhr von Dirkwagner (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „== Expansionen der Bash == === Klammerexpansion (Brace expansion) === Mit Hilfe der Klammererweiterung lassen sich beliebige Zeichenketten generieren. Im e…“)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)

Expansionen der Bash

Klammerexpansion (Brace expansion)

Mit Hilfe der Klammererweiterung lassen sich beliebige Zeichenketten generieren. Im einfachsten Fall verwendet man eine Präfix-Zeichenkette, gefolgt von beliebig vielen, mit geschweiften Klammern umschlossenen und durch Kommas getrennten Zeichen(ketten), wiederum gefolgt von einer optionalen Postfix-Zeichenkette.

Das Ergebnis sind nun Zeichenketten der Art "PräfixZeichenkette_1_Postfix", "PräfixZeichenkette_2_Postfix",..., "PräfixZeichenkette_n_Postfix".

An einem Beispiel lässt sich das Prinzip leicht verdeutlichen:

echo Beispiel{_1_,_2_,_3_}

Beispiel_1_ Beispiel_2_ Beispiel_3_

Präfix und Postfix können ihrerseits wiederum Klammererweiterungen sein und Klammererweiterungen lassen sich verschachteln, so dass sich z.B. mit nur einem Befehl eine ganze Verzeichnishierarchie erzeugen lässt:

mkdir -p bsp/{ucb/{ex,edit},lib/{bla,foo}}

du bsp | cut -b 3-
bsp/ucb/ex
bsp/ucb/edit
bsp/ucb
bsp/lib/bla
bsp/lib/foo
bsp/lib
bsp

Der Klammer-Mechanismus der eine große Menge an Zeichenketten erzeugen kann. Muster für die Klammerexpansion (brace-expanded) haben eine optionale PREAMBLE, gefolgt von einer kommaseparierten Liste von Zeichenketten zwischen einem Paar von Klammern gefolgt von einem optionalem POSTSCRIPT.

Die PREAMBLE wir jeder Zeichenkette vorangestellt, dass die Klammern enthalten, dass POSTSCRIPT wird an jede Ergebniszeichenkette abgehangen. Die Klammererweiterung kann auch verschachtelt werden. Das Ergebnis wird nicht sortiert, die links-zu-rechts-Ordnung bleibt erhalten.

echo sp{el,il,al}l spell spill spall

Die brace expansion wird vor allen anderen Expansionen ausgeführt und alle Zeichen, die für andere Expansionen eine besondere Bedeutung haben bleiben erhalten; es ist eine reine Textoperation. Die Bash führt keine syntaktische Interpretationen durch.

Um Konflikte mit der parameter expansion zu vermeiden, werden Zeichenketten die mit "${" beginnen, nicht als brace expansion verstanden.

Eine korrekt formulierte brace expansion muss eine unmaskierte öffnende und schließende Klammer besitzen und mindestens ein unmaskiertes Komma enthalten. Fehlerhaft formulierte brace expansion werden von der Bash nicht korrigiert.

Backup erstellen

cp -p /etc/apache2/plesk.conf.d/roundcube.conf{,.conf_back}

Brace expansion

Similar to filename expansion is brace expansion, which is a compact way of representing multiple similar arguments. The following four commands are equivalent:

ls file1.txt file2.txt file3.txt file4.txt file5.txt ls file{1,2,3,4,5}.txt ls file{1..5..1}.txt ls file{1..5}.txt

The first command lists each argument explicitly. The other three commands all use brace expansion to express the arguments more tersely: in the second command, all the possibilities 1 through 5 are given, separated by commas; in the third command, a numeric sequence is given ("from 1 to 5, incrementing by 1"); and the fourth command is the same as the third, but leaves the ..1 implicit.

We can also list the files in the opposite order:

ls file5.txt file4.txt file3.txt file2.txt file1.txt ls file{5,4,3,2,1}.txt ls file{5..1..-1}.txt ls file{5..1}.txt

with the default increment size being -1 when the endpoint of the sequence is less than the starting-point.

Since in Bash, the first word of a command is the program that is run, we could also write the command this way:

{ls,file{1..5}.txt}

but obviously that is not conducive to readability. (The same sort of thing, incidentally, can be done with filename expansion.)

Brace expansion, like filename expansion, can be disabled by any of the quoting mechanisms; '{', "{", or \{ produces an actual literal curly-brace.

Tildeexpansion

Beginnt der Wert mit einer unmaskierten Tilde (~), wird versucht, diese zu substituieren. Betrachtet werden alle der Tilde folgenden Zeichen bis zum ersten Schrägstrich (Slash). Ergibt dies eine gültige Benutzerkennung, so expandiert der Ausdruck zum Heimatverzeichnis dieses Benutzers.

Folgt der Tilde unmittelbar der Schrägstrich, wird der Ausdruck durch den Inhalt der Variablen HOME ersetzt; ist diese nicht gesetzt, wird das Heimatverzeichnis des aktuellen Benutzers angenommen:

var=~

echo $var
/home/user
var=~root/
echo $var
/root/

Wenn ein Wort mit einer unmaskierten tilde Zeichen ("~") beninnt,

All of the characters up to the first unquoted slash (or all characters, if there is no unquoted slash) are considered a tilde-prefix. If none of the characters in the tilde-prefix are quoted, the characters in the tilde-prefix following the tilde are treated as a possible login name.

If this login name is the null string, the tilde is replaced with the value of the HOME shell variable. If HOME is unset, the home directory of the user executing the shell is substituted instead. Otherwise, the tilde-prefix is replaced with the home directory associated with the specified login name.

If the tilde-prefix is "~+", the value of the shell variable PWD replaces the tilde-prefix. If the tilde-prefix is "~-", the value of the shell variable OLDPWD, if it is set, is substituted.

If the characters following the tilde in the tilde-prefix consist of a number N, optionally prefixed by a "+" or a "-", the tilde-prefix is replaced with the corresponding element from the directory stack, as it would be displayed by the dirs built-in invoked with the characters following tilde in the tilde-prefix as an argument. If the tilde-prefix, without the tilde, consists of a number without a leading "+" or "-", "+" is assumed.

If the login name is invalid, or the tilde expansion fails, the word is left unchanged. Each variable assignment is checked for unquoted tilde-prefixes immediately following a ":" or "=". In these cases, tilde expansion is also performed.

Consequently, one may use file names with tildes in assignments to PATH, MAILPATH, and CDPATH, and the shell assigns the expanded value.

Beispiel

export PATH="$PATH:~/testdir"

~/testdir will be expanded to $HOME/testdir, so if $HOME is /var/home/dirkwagner, the directory /var/home/dirkwagner/testdir will be added to the content of the PATH variable.

Parameterexpansion

Folgt einem Dollarzeichen $ ein Variablenname oder eine öffnende geschweifte Klammer ${...}, so spricht man von einer Variablen- bzw. Parameterexpansion.

Die geschweiften Klammern dienen zur Gruppierung und sind bei skalaren Variablen, die nicht per Parameterexpansion behandelt werden sollen, nicht notwendig.

Beginnen wir mit einem Beispiel der Expansion einer skalaren Variable ohne Parameterexpansion:

var=user

var2=~$var
echo $var2
~user
eval echo $var2
/home/user

Bemerkung

Das Beispiel verdeutlicht die Reihenfolge der Auflösung bei Zuweisung eines Wertes an "var2".

Im ersten Schritt ist die Tilde nicht auflösbar, deshalb geht sie unverändert in "var2" ein.

In einem zweiten Schritt expandiert dann der Inhalt von "var", so dass "var2" nun "~user" beinhaltet.

Um den Expansionsmechnismus zu demonstrieren, wurde eine erneute Bewertung von "var2" erzwungen (eval); nun expandiert "~user" zum Heimatverzeichnis "/home/user".

Ist das erste Zeichen eines Parameters das Ausrufezeichen, so handelt es sich um eine indirekte Expansion.

Die Bash ersetzt den Ausdruck nun nicht mehr durch den Inhalt der Variablen, sondern betrachtet den Inhalt als den Namen einer Variablen, zu deren Inhalt nun expandiert wird.

Ein Beispiel erklärt den Sachverhalt wohl deutlicher, als es Worte vermögen:

var=user

var2=var
echo $var2
var
echo ${!var2}
user

Die weiteren Mechanismen zur Parameterexpansion manipulieren den Inhalt von Variablen.

Die Beispiele werden zeigen, dass diese Form der Substitution vor allem für die Shellprogrammierung von immensem Nutzen ist und genau dort werden sie uns wieder begegnen.

»parameter« bezeichnet nachfolgend den Variablennamen und »word« steht entweder für eine Zeichenkette oder für eine Variable, die selbst wieder eine Parameter-, Kommando, Tildeexpansion oder eine arithmetische Berechnung beinhalten kann.

Variablen-Substitution

Unter Variablen-Substitution versteht man verschiedene Methoden um die Inhalte von Variablen zu benutzen.

Das umfasst sowohl die einfache Zuweisung eines Wertes an eine Variable, als auch einfache Möglichkeiten zur Fallunterscheidung. In den fortgeschritteneren Shell-Versionen (bash, ksh)existieren sogar Möglichkeiten, auf Substrings von Variableninhalten zuzugreifen.

In der Standard-Shell benutzt man für solche Zwecke üblicherweise den Stream-Editor sed. Einleitende Informationen dazu finden sich im Kapitel über die Mustererkennung).

Die folgenden Mechanismen stehen in der Standard-Shell bereit, um mit Variablen zu hantieren. Bei allen Angaben ist der Doppelpunkt optional.

Wenn er aber angegeben wird, muss die Variable einen Wert enthalten.

Variable=Wert Setzt die Variable auf den Wert.
${Variable} Nutzt den Wert von Variable. Die Klammern müssen nicht mit angegeben werden, wenn die Variable von Trennzeichen umgeben ist.
${Variable:-Wert} Nutzt den Wert von Variable. Falls die Variable nicht gesetzt ist, wird der Wert benutzt.
${Variable:=Wert} Nutzt den Wert von Variable. Falls die Variable nicht gesetzt ist, wird der Wert benutzt, und Variable erhält den Wert.
${Variable:?Wert} Nutzt den Wert von Variable. Falls die Variable nicht gesetzt ist, wird der Wert ausgegeben und die Shell beendet. Wenn kein Wert angegeben wurde, wird der Text parameter null or not set ausgegeben.
${Variable:+Wert} Nutzt den Wert, falls die Variable gesetzt ist, andernfalls nichts.

Beispiele

$ h=hoch r=runter l= Weist den drei Variablen Werte zu, wobei l einen leeren Wert erhält.
$ echo ${h}sprung Gibt hochsprung aus. Die Klammern müssen gesetzt werden, damit h als Variablenname erkannt werden kann.
$ echo ${h-$r} Gibt hoch aus, da die Variable h belegt ist. Ansonsten würde der Wert von r ausgegeben.
$ echo ${tmp-`date`} Gibt das aktuelle Datum aus, wenn die Variable tmp nicht gesetzt ist. (Der Befehl date gibt das Datum zurück)
$ echo ${l=$r} Gibt runter aus, da die Variable l keinen Wert enthält. Gleichzeitig wird l der Wert von r zugewiesen.
$ echo $l Gibt runter aus, da l jetzt den gleichen Inhalt hat wie r.

Expansion vor der Wertzuweisung an eine Variable

Bevor ein Wert einer Variablen zugewiesen wird, versucht die Bash diesen Wert nach bestimmten Regeln zu substituieren. Dabei durchläuft die Bash folgende Schritte in beschriebener Reihenfolge: # Tildeexpansion

  1. Parameter- und Variablenexpansion
  2. Kommandosubstitution
  3. Arithmetische Substitution
  4. Entfernen der »Quoting«-Zeichen

Erst jetzt erfolgt die tatsächliche Zuweisung an die Variable. Was sich hinter den einzelnen Expansionen verbirgt, soll im Anschluss an diesen Abschnitt betrachtet werden.

Das "$" Zeichen leitet eine Parameterexpansion, Kommandosubstitution oder eine arithmetische Expansion ein. Der Parametername kann in Klammern gesetzt werden, um zu verhindern, dass direkt darauf folgende Zeichen als Teil des Namens interpretiert werden. Wenn Klammern benutzt werden ist die treffende Schließende Klammer die erste "}", die nicht durch einen maskiert wurde und sich nicht innerhaltb einer eingebetteten arithmetischen Expansion, eine Komanndosubstitution oder einer Parameter-Expansion befindet.

The basic form of parameter expansion is "${PARAMETER}". The value of "PARAMETER" is substituted. The braces are required when "PARAMETER" is a positional parameter with more than one digit, or when "PARAMETER" is followed by a character that is not to be interpreted as part of its name.

If the first character of "PARAMETER" is an exclamation point, Bash uses the value of the variable formed from the rest of "PARAMETER" as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of "PARAMETER" itself. This is known as indirect expansion. You are certainly familiar with straight parameter expansion, since it happens all the time, even in the simplest of cases, such as the one above or the following:

echo $SHELL /bin/bash

The following is an example of indirect expansion:

echo ${!N*} NNTPPORT NNTPSERVER NPX_PLUGIN_PATH

Note that this is not the same as echo $N*. The following construct allows for creation of the named variable if it does not yet exist:

${VAR:=value}

Example:

echo $DIRKWAGNER

echo ${DIRKWAGNER:=Dirkwagner}
Dirkwagner

Special parameters, among others the positional parameters, may not be assigned this way, however.

Kommandosubstitution

Die Kommandosubstitution erlaubt das Ersetzen ihres Aufrufes durch ihre Ausgabe. Es existieren zwei Syntaxvarianten des Aufrufs:

$(Kommando)

`Kommando`

Die Bash führt das Kommando aus und ersetzt seinen Aufruf auf der Kommandozeile durch dessen Ausgabe, wobei abschließende Zeilenendezeichen entfernt wurden.

  1. ohne Kommandosubstitution
find / -name "whatis" 2>/dev/null | ls -l | head -5
insgesamt 15888
-rw-r--r--    1 user    users    787067 Apr  1 09:02 Buch.tar.gz
drwxr-xr-x    4 user    users      4096 Jan 16 19:49 Dhtml
drwx------    5 user    users      4096 Apr 26 09:48 Desktop
drwxr-xr-x    4 user    users      4096 Apr 21 08:43 IGLinux

# mit Kommandosubstitution
ls -l $(find / -name "whatis" 2>/dev/null)
ls -l $(find / -name "whatis"  2>/dev/null)
-rw-r--r--    1 root     root     94414 Jun 13 18:34 /usr/X11R6/man/whatis
-rw-r--r--    1 root     root    792270 Jun 13 18:34 /usr/man/allman/whatis
-rw-r--r--    1 root     root    220874 Jun 13 18:34 /usr/man/whatis
-rw-r--r--    1 root     root         0 Jun 13 18:34 /usr/openwin/man/whatis

Eine solche Kommandosubstitution kann auch bei der Zuweisung an eine Variable angewendet werden:

AktuellPfad=$(pwd)

echo $AktuellerPfad
/home/user

Zwischen Backquote (Accent Grave) gesetzte Kommandos werden ausgeführt und das Ergebnis wird dann als Parameter übergeben (d. h. die Ausgabe des Kommandos landet als Parameter in der Kommandozeile). Dabei werden Zeilenwechsel zu Leerzeichen. Braucht dieses Kommando Parameter, tritt die normale Parameterersetzung in Kraft. Zum Beispiel

echo "Aktuelles Verzeichnis: `pwd`"

Weil die verschiedenen Quotes manchmal schwer zu unterscheiden sind, wurde bei der bash eine weitere Möglichkeit eingeführt. Statt in Backquotes wird die Kommandofolge in $(...) eingeschlossen., z. B.:

echo "Aktuelles Verzeichnis: $(pwd)"

Command substitution allows the output of a command to replace the command itself. Command substitution occurs when a command is enclosed like this:

$(command) or like this using backticks: `command`

Bash performs the expansion by executing COMMAND and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.

Embedded newlines are not deleted, but they may be removed during word splitting.

echo `date`

Thu Feb 6 10:06:20 CET 2003

When the old-style backquoted (accent aigu) form of substitution is used, backslash retains its literal meaning except when followed by "$", "`", or "\".

The first backticks not preceded by a backslash terminates the command substitution.

When using the "$(COMMAND)" form, all characters between the parentheses make up the command; none are treated specially.

Command substitutions may be nested. To nest when using the backquoted form, escape the inner backticks with backslashes.

If the substitution appears within double quotes, word splitting and file name expansion are not performed on the results.

Prozesssubstitution

Die Ein- bzw. Ausgabe von Prozessen kann mittels der Prozesssubstitution mit einer FIFO-Datei verbunden werden.

Taucht ein Konstrukt der Art <(Liste) bzw. >(Liste) auf, werden die durch Liste benannten Kommandos in einer Subshell gestartet. Gleichzeitig wird die Ausgabe (>(...)) bzw. Eingabe (<(...)) der Kommandos mit einer automatisch erzeugten FIFO-Datei verbunden.

Auf der Kommandozeile erscheint nach erfolgter Substitution der Name der erzeugten FIFO-Datei.

ls <(echo "hello")

/dev/fd/63

Mit Hilfe der Prozesssubstitution könnte man den vi dazu bewegen, die Ausgaben eines Kommandos zu lesen:

vi <(ls /boot/vm*)

/boot/vmlinuz
/boot/vmlinuz.old
~

~
"/dev/fd/63" [fifo/socket] 2L, 32C
                                       1,1            All

Ein weiteres Beispiel dient zur Bestandsaufnahme laufender Prozesse:

diff <(ps ax) <(sleep 10; ps ax)

64d63
<  2129 pts/0    S      0:00 /bin/bash
67,68c66
<  2132 pts/0    R      0:00 ps ax
<  2133 pts/0    S      0:00 sleep 10
---
>  2134 pts/1    S      0:00 top
>  2135 pts/0    R      0:00 ps ax

Im Beispiel ist der Prozess top neu hinzugekommen, dass die Aufrufe der Kommandos ps und sleep erscheinen, war zu erwarten.

Und abschließend vergleichen wir die Inhalte zweier Archive:

diff <(tar tzf Buch1.tar.gz) <(tar tzf Buch.tar.gz)

325a326,328
> Images/tkinfo.gif
> Images/GlobaleVariable.gif
> Images/LokaleVariable.gif

Innerhalb der Klammern >(...), <(...) können Parameter- Kommando- sowie arithmetische Substitutionen benutzt werden.

Arithmetische Substitution

Die Bash ist kein Taschenrechner. Dennoch besitzt sie ein erstaunliches Potenzial an eingebauten Rechenoperationen, die -- nach Prioritäten geordnet -- nachfolgende Tabelle zusammenfasst:

VAR++ and VAR-- variable post-increment and post-decrement
++VAR and --VAR variable pre-increment and pre-decrement
+ - Einstelliger Operator (Vorzeichen)
! ~ Logische und bitweise Negation
** Exponentialfunktion
* / % Multiplikation, Division und Modulo-Operator
+ - Addition, Subtraktion
<< >> Bitweise Links-/Rechtsverschiebung
<= >= < > Vergleiche
== != Gleichheit und Ungleichheit
& Bitweises UND
^ Bitweises Exclusive ODER
| Bitweises ODER
&& Logisches UND
Logisches ODER
expr ? expr : expr Bedingte Zuweisung
=, *=, /=, %=, +=, -= <<=, >>=, &=, ^=, |= Zuweisungen
, separator between expressions

Als Operanden sind Konstanten und Shellvariablen (deren Inhalt als long integer betrachtet wird) erlaubt. Beginnt eine Konstante mit "0", dann wird sie als oktale Zahl verstanden; steht "0x" am Anfang, handelt es sich um eine hexadezimale Konstante.

Konstanten können zu jeder Basis zwischen 2 und 64 angegeben werden, so kann die Zahl 63 u.a. wie folgt dargestellt werden: * Zur Basis 10: 10#63

  • Zur Basis 8: 8#77
  • Zur Basis 16: 16#3f

Die so genannte arithmetische Substitution ist der gebräuchliche Weg, um Berechnungen durchzuführen: * Bash Versionen <2: Der zu berechnende Ausdruck wird in eckigen Klammern geschrieben: $[...]

  • Bash ab Version 2: Der zu berechnende Ausdruck wird in doppelte runde Klammern geschrieben: $((...)) (die alte Syntax wird weiterhin unterstützt)

Arithmetic expansion allows the evaluation of an arithmetic expression and the substitution of the result. The format for arithmetic expansion is:

$(( EXPRESSION ))

The expression is treated as if it were within double quotes, but a double quote inside the parentheses is not treated specially.

All tokens in the expression undergo parameter expansion, command substitution, and quote removal. Arithmetic substitutions may be nested.

Evaluation of arithmetic expressions is done in fixed-width integers with no check for overflow - although division by zero is trapped and recognized as an error.

The operators are roughly the same as in the C programming language. In order of decreasing precedence, the list looks like this:

Shell variables are allowed as operands; parameter expansion is performed before the expression is evaluated.

Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax.

The value of a variable is evaluated as an arithmetic expression when it is referenced. A shell variable need not have its integer attribute turned on to be used in an expression.

Constants with a leading 0 (zero) are interpreted as octal numbers. A leading "0x" or "0X" denotes hexadecimal. Otherwise, numbers take the form "[BASE'#']N", where "BASE" is a decimal number between 2 and 64 representing the arithmetic base, and N is a number in that base.

If "BASE'#'" is omitted, then base 10 is used. The digits greater than 9 are represented by the lowercase letters, the uppercase letters, "@", and "_", in that order.

If "BASE" is less than or equal to 36, lowercase and uppercase letters may be used interchangably to represent numbers between 10 and 35.

Operators are evaluated in order of precedence. Sub-expressions in parentheses are evaluated first and may override the precedence rules above.

Wherever possible, Bash users should try to use the syntax with square brackets:

$[ EXPRESSION ]

However, this will only calculate the result of EXPRESSION, and do no tests:

echo $[365*24] 8760

Übungen

b=5; b=$((b+1)); echo $b

6

a=$((b+=10)); echo $a

16

echo $((a>b?1:0))

1

echo $((8#17**2))

225

echo $((017**2))

225

echo $((-0x64*3#11%6))

-4

echo $((4<<1))

8

Wird als Operand eine Variable benutzt, so wird versucht, deren Inhalt in eine Ganzzahl zu konvertieren. Enthält die Variable keine Zahl, wird der Inhalt zu "0" konvertiert:

b="Ist b keine Zahl, wird b zu 0 konvertiert"

echo $b
Ist b keine Zahl, wird b zu 0 konvertiert

b=$(($b+1)); echo $b

1

Funktionen

Eine Funktion ist ein Name für ein Kommando oder für eine Gruppe von Kommandos.

Funktionen werden vorrangig in Shellskripten verwendet, um wiederkehrende Kommandosequenzen nicht ständig neu schreiben zu müssen.

Ein großer Vorteil von Funktionen ist, dass sich diese in einer Datei speichern lassen und diese Datei von anderen Skripten geladen werden kann.

Eine Funktion wird wie folgt definiert:

Format: [function] Funktionsname() { Kommando; [Kommando;] }

Bei der Verwendung von Funktionen sind einige Regeln zu befolgen: * Deckt sich der Name der Funktion mit einem builtin-Kommando, wird immer die Funktion ausgeführt und niemals das Kommando. Ebenso verdeckt ein Funktionsname ein gleichnamiges Kommando:

type test

test is a shell builtin
test(){ echo "ich bin eine Funktion"; }
type test
test is a function
test ()
{
echo "ich bin eine Funktion"
}
unset test* Die Funktion muss vor ihrer Verwendung definiert sein. 
  • Eine Funktion läuft in der aktuellen Umgebung, d.h. alle Variablen der Umgebung sind sichtbar und alle Variablen, die in der Funktion definiert wurden, sind auch außerhalb sichtbar:

func(){ var_in_func=xxx; }

func
echo $var_in_func
xxx* Wird eine Funktion mittels »exit« verlassen, wird auch der rufende Prozess beendet:

func(){ exit; }

func
login:* Der Rückgabewert einer Funktion ist der Rückgabewert des letzten in ihr gestarteten Kommandos: 

func(){ grep -q foo /etc/passwd; echo $?; }

func
1
echo $?
0
func(){ return 255; }
func
echo $?
255* Funktionen sind nur in der Shell ihrer Definition bekannt: 

func(){ echo "lokal"; }

bash
func
bash: func: command not found
exit
func
lokal

Einer Funktion können Parameter als Argumente übergeben werden:

Aufruf: Funktionsname [Arg1] [Arg2]...

Innerhalb einer Funktion kann auf die Parameter mittels der Positionsparameter $1..$9 zugegriffen werden. Als Beispiel dient eine Funktion "square", die die als Argument übergebene Zahl quadriert:

square() { test -z $1 && return 1; expr $1 \* $1; }

square
square 18
324

Erklärung

Das builtin-Kommando test liefert den Status "0", falls die Variable "$1" leer ist (kein Argument).

In diesem Fall wird "return 1" ausgeführt und der Funktionsaufruf beendet. expr berechnet den Ausdruck und schreibt das Ergebnis auf die Standardausgabe.

Wortzerlegung

In diesem Schritt wird die Kommandozeile in so genannte Token unterteilt. Welche Zeichen als Separatoren verwendet werden, verrät die Variable $IFS (Internal Field Separator).

Ist diese nicht gesetzt, gelten die schon erwähnten Whitespaces als Begrenzer, sofern sie nicht innerhalb von (Doppel) Anführungsstrichen stehen oder durch den Backslash "maskiert" wurden.

The shell scans the results of parameter expansion, command substitution, and arithmetic expansion that did not occur within double quotes for word splitting.

The shell treats each character of $IFS as a delimiter, and splits the results of the other expansions into words on these characters.

If IFS is unset, or its value is exactly "'<space><tab><newline>'", the default, then any sequence of IFS characters serves to delimit words.

If IFS has a value other than the default, then sequences of the whitespace characters "space" and "Tab" are ignored at the beginning and end of the word, as long as the whitespace character is in the value of IFS (an IFS whitespace character).

Any character in IFS that is not IFS whitespace, along with any adjacent IF whitespace characters, delimits a field.

A sequence of IFS whitespace characters is also treated as a delimiter. If the value of IFS is null, no word splitting occurs.

Explicit null arguments ("""" or "") are retained. Unquoted implicit null arguments, resulting from the expansion of parameters that have no values, are removed. If a parameter with no value is expanded within double quotes, a null argument results and is retained.

Datei:Grafik29.png Expansion and word splitting
If no expansion occurs, no splitting is performed.

Expansion von Dateinamen

After word splitting, unless the -f option has been set , Bash scans each word for the characters "*", "?", and "[".

If one of these characters appears, then the word is regarded as a PATTERN, and replaced with an alphabetically sorted list of file names matching the pattern.

If no matching file names are found, and the shell option nullglob is disabled, the word is left unchanged.

If the nullglob option is set, and no matches are found, the word is removed.

If the shell option nocaseglob is enabled, the match is performed without regard to the case of alphabetic characters.

When a pattern is used for file name generation, the character "." at the start of a file name or immediately following a slash must be matched explicitly, unless the shell option dotglob is set.

When matching a file name, the slash character must always be matched explicitly. In other cases, the "." character is not treated specially.

The GLOBIGNORE shell variable may be used to restrict the set of file names matching a pattern.

If GLOBIGNORE is set, each matching file name that also matches one of the patterns in GLOBIGNORE is removed from the list of matches.

The file names . and .. are always ignored, even when GLOBIGNORE is set.

However, setting GLOBIGNORE has the effect of enabling the dotglob shell option, so all other file names beginning with a "." will match.

To get the old behavior of ignoring file names beginning with a ".", make ".*" one of the patterns in GLOBIGNORE. The dotglob option is disabled when GLOBIGNORE is unset.

Metazeichen und Globbing

Damit man beim Angeben von z. B. Dateinamen nicht alle Namen eintippen muss, sondern die Dateien auch alle oder nach bestimmten Kriterien auswählen kann, gibt es Metazeichen (Jokerzeichen, Wildcards).

Metazeichen sind Zeichen mit erweiterter Bedeutung

Expansion von Dateinamen

Im Gegensatz zu anderen Systemen (z. B. Windows) werden Metazeichen von der Shell durch alle passenden Dateinamen ersetzt, bevor sie die Befehlszeile ausführt. Dies führt zu einem für Windows-Anwender ungewohntem Verhalten.

Metazeichen werden von der Shell ersetzt

Vorteile* liegt darin, dass, dass nahezu jedes UNIX-Kommando als Dateiangabe eine beliebige Menge von Dateien als Parameter haben kann.

  • So sind in Programmen keine Systemaufrufe nötig, die auf die Verzeichnisinformation zugreifen; es wird lediglich eine Schleife benötigt, welche die einzelnen Dateien nacheinander bearbeitet.

Praktisches Globbing

Ganz schlecht

chmod a+r witzig1.jpg

chmod a+r witzig2.jpg
chmod a+r witzig3.jpg

Besser

chmod a+r witzig1.jpg witzig2.jpg witzig3.jpg

Super

chmod a+r *.jpg

Es gibt folgende Metazeichen

* Der Stern steht für eine beliebige Zeichenfolge - oder für überhaupt kein Zeichen.

"ab*" steht für alle Dateinamen, die mit "ab" anfangen, auch für "ab" selbst ("ab", "abc", "abcd", "abxyz", usw.).

? Das Fragezeichen steht für genau ein beliebiges Zeichen. Zum Beispiel

"?bc" steht für alle Dateinamen mit 3 Zeichen, die auf "bc" enden ("abc", "bbc", "1bc", "vbc", "xbc", usw.), nicht jedoch für "bc".

[...] Im einfachsten Fall steht es für genau ein Zeichen aus der Menge (bspw. "[aeiou]" für einen Vokal).

Diese Angabe kann negiert werden ("alle außer diese Zeichen"), indem das erste Zeichen nach [ ein ! oder ^ ist ("[!abc]" bzw. "[^abc]").

Anstatt einzelne Zeichen aufzuzählen, lassen sich Bereiche angeben ("[a-z]" meint alle Kleinbuchstaben).

Wichtig!

Der * ist ein gefährliches Zeichen, Tippfehler könne zum Fiasko führen, wenn aus Versehen ein Leerzeichen zuviel getippt wird.

rm a* löscht beispielsweise alle Dateien, die mit "a" anfangen.

rm a * löscht dagegen erst die Datei "a" und dann alle Dateien im Verzeichnis. 

Zeichenbereiche

Außer grep und Regulären Ausdrücken, gibt es eine gute Auswahl an pattern matching, dass die Shell direkt durchführen kann, ohne dass dafür externe Programme eingesetzt werden müssen.

Bekannt sind sicherlich das Sternchen (asterisk) „*“ und das Fragezeichen (question mark) „?“, die jede Zeichenkette oder jeden Buchstaben filtern. Um diese Sonderzeichen als Literale zu filtern müssen sie maskiert werden:

touch "*" ls "*"

But you can also use the square braces to match any enclosed character or range of characters, if pairs of characters are separated by a hyphen. An example:

ls -ld [a-cx-z]* drwxr-xr-x 2 dirkwagner dirkwagner 4096 Jul 20 2002 app-defaults/ drwxrwxr-x 4 dirkwagner dirkwagner 4096 May 25 2002 arabic/ drwxrwxr-x 2 dirkwagner dirkwagner 4096 Mar 4 18:30 bin/ drwxr-xr-x 7 dirkwagner dirkwagner 4096 Sep 2 2001 crossover/ drwxrwxr-x 3 dirkwagner dirkwagner 4096 Mar 22 2002 xml/

This lists all files in dirkwagner's home directory, starting with "a", "b", "c", "x", "y" or "z".

If the first character within the braces is "!" or "^", any character not enclosed will be matched.

To match the dash ("-"), include it as the first or last character in the set.

The sorting depends on the current locale and of the value of the LC_COLLATE variable, if it is set.

Mind that other locales might interpret "[a-cx-z]" as "[aBbCcXxYyZz]" if sorting is done in dictionary order.

If you want to be sure to have the traditional interpretation of ranges, force this behavior by setting LC_COLLATE or LC_ALL to "C".

Nullglob

Ohne Match wird das Argument unverändert übernommen. Dieses Verhalten lässt sich mit der Shelloption nullglob beeinflussen.

Match - gefundene Dateien werden übernommen

echo a1*.jpg

a1.jpg a10.jpg a11.jpg

Kein Match - Argument bleibt unverändert

echo b1*.jpg

b1*.jpg

Dotfiles

Der Punkt am Anfang von Dateinamen stellt eine Ausnahme dar, er muss explizit angegeben werden (wegen der Verzeichnisreferenzen "." bzw. ".." und der Tatsache, dass Dateien, die mit einem Punkt beginnen, normalerweise nicht angezeigt werden). * Dateien, die mit "." beginnen sind versteckt

  • Shell Globbing ignoriert die "Dotfiles"
  • Punkt muss explizit genannt werden

echo .*

. .. .bash_history .bash_profile .bashrc

Globbing und Brace Expansion

Brace Expansion hat starke Ähnlichkeit mit Globbing doch die angegebenen Dateinamen müssen nicht existieren.

ls

a1.jpg a10.jpg a11.jpg a2.jpg a3.jpg a4.jpg

"{name1,name2}" - Alternativen aufzählen

echo a{2,10}.jpg

a2.jpg a10.jpg

Zeichenklassen

Zeichenklassen können mit folgender Syntax in eckigen Klammen angegeben [:CLASS:]. Dabei wird CLASS nach POSIX-Standard angegeben und kann folgende Werte annehmen:

"alnum", "alpha", "ascii", "blank", "cntrl", "digit", "graph", "lower", "print", "punct", "space", "upper", "word" or "xdigit"

ls -ld digit:* drwxrwxr-x 2 dirkwagner dirkwagner 4096 Apr 20 13:45 2/

ls -ld upper:* drwxrwxr-- 3 dirkwagner dirkwagner 4096 Sep 30 2001 Nautilus/ drwxrwxr-x 4 dirkwagner dirkwagner 4096 Jul 11 2002 OpenOffice.org1.0/ -rw-rw-r-- 1 dirkwagner dirkwagner 997376 Apr 18 15:39 Schedule.sdc

Wenn die Shell-Option extglob aktiviert ist, werden erweiterte pattern matching Operatoren erkannt.

Extglob (erweitertes Globbing)

Die ksh88 führte zusätzlich die erweiterte Mustererkennung ein. Diese sind vergleichbar mit der Leistung Regulärer Ausdrücke, die Notation ist ähnlich, aber nicht gleich. Wenn die Shelloption extglob eingeschaltet ist, unterstützt auch die Bash diese Optionen.

Wenn möglich, sollte die erweiterte Mustererkennung regulären Ausdrücken vorgezogen werden, da diese effizienter und damit deutlich schneller ausgewertet werden können. Die Muster sind eine Liste von Zeichenketten, die durch | getrennt sind.

Das Zeichen vor der öffnenden Klammer reguliert die Auswertung des Musters:

?(Muster-Liste) Kein oder ein Auftreten eines Musters
*(Muster-Liste) Kein oder mehrere Auftreten eines Musters
+(Muster-Liste) Ein oder mehrere Auftreten eines Musters
@(Muster-Liste) Genau ein Auftreten eines Musters
!(Muster-Liste) Alle außer den angegebenen Mustern

Die erweiterte Mustererkennung kann mit Standard-Shell-Wildcards kombiniert und verschachtelt werden.

Übungen 1

  1. Vorbereitung

mkdir ~/gob && cd ~/gob

touch a aa aaa b bb bbb c cc ccc d dd ddd# Beliebig viele beliebige Zeichen (*)

ls a*

a  aa  aaa# Ein beliebiges Zeichen (?)

ls a?

aa# Ein Zeichen aus einer Menge [...]

ls [abc]

a  b  c# Ein Zeichen aus einem Bereich [ - ]

ls [a-d]

a  b  c  d# Kein Zeichen aus der Menge [! ]

ls [!ab]*

c  cc  ccc  d  dd  ddd# Kein Zeichen aus einem Bereich [! - ]

ls [!a-c]*

d  dd  ddd

Übungen 2

  1. Vorbereitung:

mkdir ~/extgob && cd ~/extgob

touch 1 11 111 2 22 222 3 33 333 
touch a aa aaa b bb bbb c cc ccc# ?(Muster-Liste)- kein oder ein Auftreten eines Musters

ls ?(a|b)

a  b# *(Muster-Liste) - kein oder mehrere Auftreten eines Musters

ls *(a|b)

a  aa  aaa  b  bb  bbb# +(Muster-Liste) - ein oder mehrere Auftreten eines Musters

ls +(a|b)

a  aa  aaa  b  bb  bbb# @(Muster-Liste) - genau ein Auftreten eines Musters

ls @(a|b)

a  b# !(Muster-Liste)- alle außer den angegebenen Mustern 

ls !(a|b)

1  11  111  2  22  222  3  33  333  aa  aaa  bb  bbb  c  cc  ccc# .!(|.)  - Dotfiles ohne "." und ".."

ls -d .!(|.)

.bash_history .bash_profile .bashrc# Zeichenklasse:

ls alpha:

a  b  c# Kombinationen

ls +(digit:)

1  11  111  2  22  222  3  33  333

ls ?(digit:)

1  2  3

ls +(digit:|!(upper:))

1  11  111  2  22  222  3  33  333  a  aa  aaa  b  bb  bbb  c  cc  ccc