Kurzüberblick Linux Shell (Bash, Ash)
Winfried Mueller, www.reintechnisch.de, Start: 10.12.2003
Grundlagen
- erste Zeile im Skript gibt den Interpreter an
#!/bin/ash
#!/bin/bash
- alles hinter # ist Kommentar
- x-permission setzen, damit es ausgeführt werden kann
- Backticks: Kommando in Subshell und Zuweisung stdout
cd /etc
a=`pwd` # >> /etc
- File include: mittels . Operator
#!/bin/bash
. Foo # Datei Foo wird included
- Variable für ein Subshell übergeben, Environment belassen
COLUMNS=240 dpkg --list #COLUMNS ist im Environment
#von dpkg, nicht aber in der
#Muttershell
- Boolesche Operationen anders als in C:
- true ist 0
- false ist alles andere, man sollte aber 1 verwenden
- $ false
$ echo $? # >> 1
$ true
$ echo $? # >> 0
- Globbing:
- bezeichnet die Auflösung von Platzhalter/Jokerzeichen
wie *,? für Dateinamen.
- ? : Ein beliebiges Zeichen.
- * : Beliebige Anzahl eines beliebigen Zeichens.
- []: Eines der Zeichen, was zwischen den Klammern steht.
Bsp:
syslog.[0-9].gz # >> syslog.1.gz, syslog.2.gz...
ab[CDEF] # >> abC, abD, abE, abF
ab[!0-9] # >> abA, nicht jedoch ab0, ab1, ab2...
ab[0-9A-Z]k # >> ab0k, ab1k, abAk, abZk...
- {}: Brace Extension: Angegebene Wörter ersetzen.
Schachtelung möglich.
Bsp:
mail.{info,err} # >> mail.info, mail.err
- Quoting:
- "text $x": Inhalt von Variablen wird ersetzt. Globbing findet
nicht statt. Sonderzeichen werden intepretiert.
- 'text $x': Keine Ersetzung, Sonderzeichen wie $, \, ` oder "
werden nicht interpretiert.
- `befehl` : Variablen werden ersetzt, globbing findet statt.
Befehl wird ausgeführt und dessen stdout
zurückgegeben.
- Quoting fast mehrere Wörter zu einem Wort zusammen:
Bsp:
a=Hello World # >> Fehler
a="Hello World" # >> OK
- Escape:
- Folgende Zeichen müssen in Strings geschützt werden:
\$, \`, \\, \#
- Pipes:
- verbinden von mehreren Programmen über Pipes, wobei stdout eines
Programms an stdin des nächsten weitergeleitet wird.
Bsp:
$ cat /etc/fstab | grep "hda1"
$ ls -l | less
- Exitstatus ist der Status des letzten Befehls in der Pipe.
Ein/Ausgabe-Umleitung
- Eingabeumleitung:
Bsp:
$ cat < /etc/fstab # Datei wird an stdin von cat weitergeleitet
- Ausgabeumleitung
Bsp:
$ cat /etc/fstab > /tmp/tmp1.txt # Umleitung stdout in Datei
$ cat /etc/fstab >> /tmp/tmp1.txt # Anhängend umleiten
$ cat /etc/fstab 2> /dev/null # Fehlerausgaben stderr unterdrücken
$ cat /etc/fstab 2>&1 # Fehlerausgaben auf stdout umlenken
$ cat /etc/fstab 1>&2 # Alle Ausgaben nach stderr
Vordefinierte Variablen
$0 | Name des Skriptes (ohne Pfad) |
$1..$9 | übergebene Parameter des Skriptes; auch Argumente einer Funktion |
$# | Anzahl übergebene Parameter |
$? | Exitstatus des letzten Befehls |
$RANDOM | Zufallszahl Integer |
$SHLVL | Gibt an, wieviele Shells ineinander verschachtelt sind |
$OSTYPE | Betriebssystem-Typ |
$LINENO | aktuelle Zeile im Skript, die gerade abgearbeitet wird |
$MACHTYPE | Maschinentyp |
$GROUPS | alle Gruppen, in der sich der aktuelle Benutzer befindet (array) |
Kontrollstrukturen
- bei allen Bedingungen, wird ein Befehl ausgeführt und
der Exit-Code dieses Befehls ausgewertet. 0=true,
alles andere = false
- weil der Befehl test sehr oft verwendet wird, gibt es
in der bash und ash eine Abkürzung:
test <Bedingung> entspricht [ <Bedingung> ]
(Leerzeichen um die eckige Klammern nicht vergessen, weil
'[' auch nichts weiter als ein Befehl ist, der test aufruft
und die schließende ']' schluckt.)
- if <befehl> ;then
<befehle>;
[ elif <befehl> ;then
<befehle> ] ...
[ else
<befehle> ]
fi
Bsp:
if test -d /tmp ;then
echo "Temp Verzeichnis vorhanden"
fi
if [ -d /tmp -a -L /tmp ]
then
echo "Temp Verzeichnis vorhanden und ist ein Link"
fi
- case <ausdruck> in
<fall1>) <befehle> ;;
<fall2>) <befehle> ;;
...
esac
Bsp:
a="Test hier"
case "$a" in
"Test"*)
echo "a fängt mit Test an."
;;
"Foo")
echo "a ist Foo"
;;
"Bar" | "Sonst")
echo "a ist Bar oder Sonst"
;;
esac
- while <befehl> ;do
<befehle>
done
- until <befehl> ;do
<befehle>
done
- for <var> in <wort> ;do
<befehle>
done
- break, continue
- break bricht eine Schleife ab
- continue startet sofort den nächsten Durchlauf
Shell Verhalten beeinflussen
- Benutzung undefinierter Variablen = Fehler
set -u # einschalten
set +u # ausschalten
bash -u <script>
echo $c # >> bash: c: unbound variable
- Debugging: Jedes Kommando ausgeben bei Abarbeitung
set -x # einschalten
set +x # ausschalten
- Datei /etc/profile
- systemweite Startdatei für Login-Shells
- Datei ~/.profile
- benutzerspezifische Startdatei für Loginshell
- Datei /etc/bash.bashrc
- systemweite Startdatei für Nich-Login-Shells
(nur bash)
- Datei ~/.bashrc
- benutzerspezifische Startdatei für jede
Nicht-Login-Shell (nur bash)
Variablen
- erlaubte Zeichen: [A-Za-z_][A-Za-z_0-9]*
- Zuweisung:
a=10
str='Hello World'
str2="Ich bin $a Jahre alt."
- normale Variablen leben solange, wie das Skript läuft
- Benutzung:
- $ voranstellen, um den Wert auszulesen, oder ${var_name}
a=10
echo $a # >> 10
echo a # >> a
b=a # >> a
b=$a # >> 10
echo "Das Skript laeuft ${n}mal" # ${n} anstatt $n
- Listenexpansion/Globbing wird wird unterdrückt,
wenn in doppelte Anführungsstriche
a='/etc/*'
echo $a # >> alle Files unter etc
echo "$a" # >> /etc/*
- $ Entwertung duch \
echo \$a # >> $a
- lokale Variablen in Funktionen
- sind nach außen nicht sichtbar, verändern nicht
außen definierte Variablen.
- local a
- local b=10
- Variablen mit export zum Environment hinzufügen
- Subshell erben das Environment, so auch dort
verfügbar; erben = eigene Kopie des Environments
- nicht exportiere Variablen sind für Subshells
unsichtbar
-
- a=10
export a
export a=10 # Zuweisung + export geht in bash
- Arrays
- anlegen:
a[10]=10
a[9]="Hello"
- auslesen:
echo ${a[10]}
echo ${a[9]}
echo ${a[*]} # alle Werte durch Space getrennt ausgeben
echo ${a[@]} # identisch in diesem Fall
- Mehrfachzuweisung:
a=(1 10 Hello Test) # >> ${a[0]}=1; ${a[1]}=10; ${a[2]="Hello"}...
- Länge eines Eintrages
echo ${#a[2]} # >> 5 bei obigen Beispiel "Hello"
- Anzal der Einträge
echo ${#a[*]} # >> 4 in obigen Beispiel
Wichtige Befehle
export var
- ohne Parameter oder mit -p Anzeige des Environments
- export von Variablen, siehe unter Variablen
unset var
- Environmentvariable löschen
unset Foo
shift [n]
- verschiebt alle Übergabeparameter nach links, $1 fällt
raus, $2 wird zu $1 usw. Mit n kann man angeben, um wieviel
Positionen geshiftet wird. Default = 1
exit [n]
- Skript verlassen/beenden. Wert 0 steht für normale Beendung.
Fehler können mit Fehlerwerten 1-255 zurückgegeben werden.
true und false
- true gibt 0 zurück, false gibt 1 zurück
env oder printenv
- listet das Environment auf, ähnlich export ohne Parameter
expr
- Berechnungen durchführen, Integer Arithmetik
- String Regexp-Vergleiche
- substr-Vergleiche
- String-Länge
- Leerzeichen zwischen Wert und Operator nicht vergessen
- quoting einiger Sonderzeichen (Operatoren) nicht vergessen
- Bsp:
$ echo `expr 3 + 2` # >> 5
$ x=1; x=`expr $x + 1`; echo $x # >> 2
$ echo `expr 3 + 2 \* 5 - 1 / 2`
tail
head
tee
- stdout wird sowohl nach stdout wie auch in eine Datei
verzweigt. So kann man sich Programmausgaben sowohl auf
der Konsole anschauen wie auch zusätzlich in eine Datei
schreiben.
Bsp:
$ grep "err" /var/log/syslog | tee /tmp/errlist.txt
test
- wird häufig verwendet zum Testen aller möglichen Bedingungen.
Ausdruck Beispiel Erklärung
-d file [ -d /etc ] Wahr, wenn file ein Directory
-f file [ -f fstab ] Wahr, wenn File existiert
-r file [ -r fstab ] Wie -f und Leseberechtigung
-w file [ -w fstab ] Wie -f und Schreibberechtigung
-x file [ -x shred ] Wie -f und Ausführberechtigung
-L file [ -L /tmp ] File ist ein symbolischer Link
-h file identisch mit -L
-g file [ -g /tmp ] Wahr, wenn gid Bit gesetzt
-k file Wahr, wenn Sticky Bit gesetzt
-u file Wahr, wenn suid Bit gesetzt
file1 -nt file2 Wahr, wenn file1 neuer als file2
file1 -ot file2 Wahr, wenn file1 älter als file2
-z string [ -z $str ] Wahr, wenn String Länge 0 hat.
-n string [ -n $str ] Wahr, wenn String nicht leer ist.
str1 = str2 [ "a" = "a" ] Wahr, wenn Strings identisch.
str1 != str2 [ "a" != "A" ] Wahr, wenn Strings ungleich.
z1 -eq z2 [ 10 -eq 10 ] Wahr, wenn z1 gleich z2
z1 -lt z2 [ 10 -lt 20 ] Wahr, wenn z1 < z2
z1 -le z2 [ 10 -le 20 ] Wahr, wenn z1 <= z2
z1 -ne z2 [ 10 -ne 20 ] Wahr, wenn z1 <> z2
z1 -gt z2 [ 10 -gt 20 ] Wahr, wenn z1 > z2
z1 -ge z2 [ 10 -ge 20 ] Wahr, wenn z1 >= z2
! ausdruck [ ! 1 -ge 2 ] Kehrt Ausdruck um
ausd1 -a ausd2 [ -z $a -a -z $b ] Und Verknüpfung
ausd1 -o ausd2 [ -z $a -o -z $b ] Oder Verknüpfung
type Name
zeigt an, wie Name interpretiert werden würde
-t : gibt alias, keyword, function, builtin, file zurück, je
nachdem, wie der Name interpretiert würde.
-a : Ausgabe aller Speicherorte, wo dieses ausführbare File
gefunden werden kann.
file file
- Type/Format des Files zurückgeben
- lässt sich erweitern über /etc/magic
- file ist nicht gut portabel
echo text
- Ausgabe Text auf stdout
-n verhindert Ausgabe von newline
printf format arg...
- Formatierte Ausgabe
read var
- Eingaben von stdin entgegennehmen und in var ablegen
- von anderen Kanälen lesen:
read pass <&4
env [NAME=VALUE]...[COMMAND [ARG]...]
- Ein Programm mit verändertem Environment aufrufen.
- ohne Parameter listet es das Environment auf
tr [OPTION]...SET1 [SET2]
- Filterwerkzeug, was auf stdin empfängt und auf stdout ausgibt
- löschen einzelner Zeichen
echo "Hello World" | tr -d "or" # >> Hell Wld
- löschen von Wiederholungen eines Zeichens
echo "Hello Worldddd" | tr -s "ld" # >> Helo World
- Ersetze alle Zeichen in SET1 durch SET2
echo "ABCDEFGHI" | tr "ABC" "abc" # >> abcDEFGHI
- Ersetze alle Zeichen, die nicht in SET1 stehen durch SET2
echo "ABCDEFGHI" | tr -c "ABC\n" "X" # >> ABCXXXXX
Wichtige Environment-Variablen
PATH | Suchpfad, durch Doppelpunkt getrennt |
HOME | Homeverzeichnis des aktuellen Benutzers |
PS1 | Festlegung des Eingabe-Prompts |
PWD | aktuelles Verzeichnis |
OLDPWD | vorheriges Verzeichnis |
SHELL | derzeit ausgeführte Shell |
USER | Benutzername des aktuellen Benutzers |
LOGNAME | Name es eingeloggten Benutzers |
MAIL | Posteingangs-mbox |
TERM | verwendetes Terminal |
Funktionen
- Definition
- function MyFunction () # bash typisch, ash nicht
{
# Code
}
- MyFunction () # ash, geht aber auch bei bash
{
# Code
}
- Variablenübergabe mit $1, $2 usw.
function Foo ()
{
local src_file=$1
local dst_file=$2
# ...
}
Here Documents
- eine spezielle komfortable Art, längere Texte im Quelltext
zu verfassen. Dieser Text wird auf stdin eines Kommandos geleitet.
Text wird eingefasst von <<MARKE bis MARKE. MARKE
kann dabei ein beliebiges Wort sein.
- Bsp:
s1="EinBeispielSkript"
s2="0.0.1"
cat <<ENDE
Das ist ein langer Text,
der sich über mehrere Zeilen,
erstreckt. Genau so, wie ich den
hier eintippe, so erscheint er später
bei der Ausgabe. Das Skript heißt $s1
und hat die Release: $s2
ENDE
- Anfangs- und Endemarke müssen identisch sein, keine Leerzeichen dahinter
hängen. Endemarke muss einzeln auf Zeile stehen.
- Ideal, um Texttemplates mit Variablenwerten zu ersetzen, z.B. für dynamische
Erzeugung von Websites oder für Serienbriefe.
Tricks
Umleitung eines Blocks
- Die Ausgaben in einem Block können gesammelt umgeleitet werden
Bsp:
if true
echo "Hello"
echo "Hello"
fi >> test.txt
Pitfalls
- Variablenzuweisung keine Leerzeichen
a=10 # ok
a = 10 # err
a= 10 # err
- Bei expr immer Leerzeichen verwenden
expr 20 / 10 #ok
expr 20/10 #err
- Variablen, die einen Dateinamen beinhalten, sollten immer in "
geschrieben werden, weil sie Leerzeichen enthalten können.
Bsp:
ls "$f"
Tastenkombinationen
- strg+s - XOFF
- strg+q - XON
- strg+d - Abschluss diverser Programme, z.B. mail