Diese Seite ist optimiert für eine Auflösung von min. 1280x1024.

facebook   google   twitter   digg   email  





Bash



Was ist die Bash?

Bash steht für Bourne again shell und ist eine der populärsten Shells. Neben der Bash gibt es noch die csh (C-Shell), ksh (Korn-Shell), dsh (Dancer oder Distributed Shell) - eine sehr nützliche Shell um Befehle auf vielen Servern gleichzeitig abzusetzen, rsh (Restricted Shell) und noch einige mehr. Die Bash ist ein sh kompatibler Kommandozeilensrprachen Interpreter, welcher von der Standarteingabe oder aus einer Datei seine Befehle bekommen kann.

Konfiguration der Bash

Die Bash kann man - wie so ziemlich alles unter Linux - recht gut und umfangreich konfigurieren. Dies ist an verschiedenen Stellen möglich. Viele Einstellungen sind in Variabeln gespeichert die man sich mittels einem echo $VARIABELNNAME ausgeben lassen kann. Diese Variabeln kann man auf der Kommandozeile für die Dauer einer Sitzung direkt manipulieren um so das Verhalten der Bash zu ändern. Einige der bekanntesten Variabeln kann man sich mittels env (enviroment) anzeigen lassen. All diese Variabeln werden "hart" gesetzt, sprich sie stehen in Konfigurationsdateien und um sie nicht immer von Hand ändern zu müssen kann man diese dort direkt ändern. Man unterscheidet zwischen globalen und lokalen Konfigurationsdateien. Diese Dateien werden wie folgt verarbeitet: Beim starten der Bash liest die Bash zuerst die globale Konfiguration ein und anschliessend lokale Konfigurationsdateien. Somit kann man für den Server global eine Konfiguration setzen die halbwegs etwas taugt aber jeder User kann sich "seine Bash" noch weiter konfigurieren, wenn ihm die globale Konfiguration nicht ausreicht. Die meisten Optionen hierzu werden (wie bereits beschrieben) in Variabeln gespeichert und können nach dem Schema ARIABLE="Wert" angegeben werden. Die Konfigurationsdateien unterscheiden sich von Distribution zu Distribution ein klein wenig. In der Regel findet man sie hier:
/etc/bash.profile oder profile.bash oder nur profile - globale Einstellungen
/etc/inputrc - globale definition von Tastatur-Shortcuts
In seinem Home-Dir kann man sich zusätzlich noch eigene Konfigurations-Dateien anlegen:
~/.bashrc
~/.bash_logout
~/.bash_profile
Keine Konfigurationsdatei, aber trotzdem interessant. Hier wird die Historie der Bash gespeichert:
~/.bash_history

Syntax der Bash

Im Allgemeinen erwartet die Bash immer einen Befehl (ausführbares Script) auf der Kommandozeile. Ein Befehl kann Optionen mit sich bringen was meisens der Fall ist) und man kann in aller Regel auch Parameter übergeben. Demnach steht schon die Syntax: befehl . Verschiedene Optionen werden in der Regel durch Leerzeichen getrennt, Parameter durch Komma. Die Zuweisungen Parameter zu Option erfolgt dabei meist mittels einem Leerzeichen, kann aber auch durch ohne Leerzeichen erfolgen indem man den Parameter direkt hinter die Option schreibt:
pux@onkelpeter:~$ ping -c1 onkelpeter.de
pux@onkelpeter:~$ ping -c 1 onkelpeter.de
pux@onkelpeter:~$ cut -d: -f1,2 .bashrc
pux@onkelpeter:~$ dig axfr onkelpeter.de

Zuweisungen in der Bash

Werte und/oder Zuweisungen werden in der Bash in Variabeln "aufgehoben". Dazu muss man wissen, wie man sich eine Variable ausgeben lässt bzw. wie man eine solche setzen kann. Eine Variable deklariert man so hier:
pux@onkelpeter:~$ VAR="wert";
pux@onkelpeter:~$ 
Ausgeben lässt man sie sich wiederum mit einem simplen echo-Befehl:
pux@onkelpeter:~$ echo $VAR
wert
pux@onkelpeter:~$ 
Es wird nach Gross- und Kleinschreibung unterschieden, aber es ist irrelevant, ob man seine Variabeln gross oder klein schreibt. Ein kleines Beispiel dazu:
pux@onkelpeter:~$ VAR=peter
pux@onkelpeter:~$ var=onkel
pux@onkelpeter:~$ echo $VAR
peter
pux@onkelpeter:~$ echo $var
onkel
pux@onkelpeter:~$ 
Schaut man sich nun eine Bash-Konfigurations-Datei an, wird das zuweisen von Werten nun etwas verständlicher:
pux@onkelpeter:~$ cat .bashrc | grep =
export HISTCONTROL=ignoredups
export HISTFILESIZE=1000000
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
export CVS_RSH=ssh
export FCEDIT=vim
export EDITOR=vim
PATH="${PATH}":~/bin;
PS1='\u@\h:\w\$ '
[...]

Die Path-Variable

Die PATH-Variable hat unter Linux den gleichen Zweck, wie unter Windows; In Ihr wird der Suchpfad angegeben, in dem nach einem Script/einer Anwendung zu suchen ist. Ausgeben lassen kann man sich diese mit einem echo $PATH:
pux@onkelpeter:~$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/games:/home/pux/bin
pux@onkelpeter:~$ 
Wie zu sehen ist, fehlt ein wichtiger Pfad: Das aktuelle Arbeitsverzeichnis (./)! Aber warum ist das so? Das hat einen einfachen Hintergrund. Stellen wir uns mal vor, dass ein Benutzer in seinem Verzeichnis ein Script mit dem Namen "cp" hinterlegt, das z.B. ein "rm -rf /" beinhaltet. Dann würde ein Administrator beim Versuch, eine Datei zu kopieren, in Wirklichkeit alle Dateien des Servers löschen.
Wichtig ist dabei zu wissen: Die Path-Variable wird von links nach rechts abgearbeitet, sprich findet die Bash den Befehl im ersten genannten Verzeichnis ist sie zufrieden und es wird in den anderen Pfaden nicht weitergesucht. Der Eintrag "./" müsste also ganz als erstes in der PATH-Variable stehen, damit das o.g. Beispiel klappen würde. Aus diesem Grund definiert man (wenn man den PATH schon neu definieren möchte) auch immer in dieser Reihenfolge: PATH=$PATH.":/neuer/pfad" und niemals PATH="/neuer/pfad:".$PATH.

Autovervollständigug

Um auf der Kommandozeile nicht zuviel Tippen zu müssen, erfand man die "tab"-Taste. Mit der kann man Befehle oder Pfade automatisch vervollständigen. nehmen wir mal die folgende Struktur an:
pux@onkelpeter:~$ ls -al
drwxr-xr-x  5 pux pux       4096  3. Apr 12:55 foo
drwxr-xr-x  8 pux pux       4096  3. Apr 12:53 mooh
drwxr-xr-x  4 pux pux       4096 15. Sep 2008  bin_new
pux@onkelpeter:~$ 
Will man nun in das Verzeichnis "bin_new" wechseln, so kommt man mit wenigen Eingaben zum Ziel:
cd b
vervollständigt zu:
cd bin_new
Gibt es mehrere Möglichkeiten - z.B. bin_new, bin_old - dann vervollständigt nur bis zur nächsten "Möglichkeit":
cd b
vervollständigt zu:
cd bin_
cd bin_n
vervollständigt dann erst zu:
cd bin_new

man-Pages

man-Pages sind das Hilfesystem unter Linux. Mit ihnen kann man sich Hilfe zu fast allem anzeigen lassen. Einfach "man befehl" eingeben und los geht's. Es geht sogar man man. Die Hilfeseiten für die Hilfe. Zu erähnen ist noch, dass es unterschiedliche Sektionen gibt. Ein "man 1 befehl" gibt etwas anderes aus, als ein "man 8 befehl". Die man-Pages sind in verschiedene Abschnitte (Sections) eingeteilt - abhängig von ihrem Einsatzzweck. Die Benutzerbefehle finden sich im Abschnitt 1, die Systemaufrufe von UNIX sind im Abschnitt 2 dokumentiert usw. Die Abschnitte 1, 4 (Dateiformate) und 8 (Systemverwaltung) werden dich am meisten interessieren. Interessant ist auch noch der Befehl apropos. Damit kann man die Manpages durchsuchen:
pux@onkelpeter:~$ apropos kill
kill (1)             - beendet einen Prozess
killall (1)          - kill processes by name
killall5 (8)         - send a signal to all processes.
pkill (1)            - look up or signal processes based on name and other attributes
skill (1)            - send a signal or report process status
xkill (1)            - kill a client by its X resource
XKillClient (3)      - control clients
yes (1)              - output a string repeatedly until killed
pux@onkelpeter:~$
Die Nummer hinter dem Suchbegriff gibt die "Section" an. Es gibt auch noch whatis. Dieses gibt Suchergebnisse mit exakt dem gesuchten Stichwort aus. Beim Beispiel von kill:
pux@onkelpeter:~$ whatis kill
kill (1)             - send a signal to a process
pux@onkelpeter:~$
Sucht man z.B. nach ps, macht whatis Sinn, da mit "apropos ps" sehr viele Ergebnisse gezeigt werden.

history

Die Historie der Bash wird gespeichert. Das heisst, tippt man einen Befehl ein, so wird dieser "gespeichert". Das passiert für geöhnlich in der Datei ~/.bash_history. Wie viel und in welchem Format dort gespeichert wird, kann man mit verschiedenen Variabeln konfigurieren. Die wichtigsten dabei sind HISTCONTROL, HISTFILESIZE und HISTTIMEFORMAT. Es gibt noch eine menge mehr (man history), aber diese 3 erwähne ich kurz. Mittels HISTCONTROL und dem Parameter "ignoredups" kann man definieren, dass doppelte Einträge nicht in der Historie landen (mehrmaliges nacheinanderfolgendes "ls" z.B. taucht dann nur einmal auf). HISTFILESIZE gibt an, wieviel Speicherplatz benutzt werden darf um die Historie abzulegen. Default sind das round about 500 Zeilen, ich mag lange Historien aber, so kann man länger nachvollziehen, was gemacht wurde. Und zuletzt HISTTIMEFORMAT. Damit kann man einen Zeitstempel definieren. So sieht man auch, wann das entsprechende Kommando eingegeben wurde. Damit man das nach einem Login/öffnen einer Shell nicht immer wieder neu definieren muss, haut man es am besten in die .bashrc/.bash_profile rein:
pux@onkelpeter:~$ cat .bashrc | grep HIST
export HISTCONTROL=ignoredups
export HISTFILESIZE=1000000
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "
pux@onkelpeter:~$ 
Ein "history" gibt dann übrigens sowas hier aus:
pux@onkelpeter:~$ history | tail
 1174  2009-04-06 10:16:52 cvs up
 1175  2009-04-03 15:26:56 ssh onkelpeter.de
 1176  2009-04-06 10:19:57 root
 1177  2009-04-06 10:53:36 pinky 
 1178  2009-04-06 10:54:01 man .gnashrc
 1179  2009-04-06 10:54:04 cd /home/pux
 1180  2009-04-06 10:54:05 ls
 1181  2009-04-07 08:17:59 cd bin
 1182  2009-04-07 08:20:15 ls
 1183  2009-04-07 08:26:22 date
pux@onkelpeter:~$ 
Die history kann noch einiges mehr. Was man öfters mal braucht, ist z.B. den letzten Befehl, aber mit anderen Parametern. Z.B. wenn man "viel" eingibt, und nur ein Wort tauschen möchte, kann man das schnell ändern:
pux@onkelpeter:~$ ssh onkelpeter.de 'hostname; uptime; ls /var | wc -l';
onkelpeter.de
 08:31:16 up 22 days,  9:15,  0 users,  load average: 9.49, 10.51, 9.69
17
pux@onkelpeter:~$ ^onkelpeter.de^server23^
ssh infong43 'hostname; uptime; ls /var | wc -l';
server23
 08:31:23 up 42 days,  3:53,  1 user,  load average: 3.31, 4.28, 4.75
17
pux@onkelpeter:~$ history | tail -n3
 1186  2009-04-07 08:31:31 ssh onkelpeter.de 'hostname; uptime; ls /var | wc -l';
 1187  2009-04-07 08:31:37 ssh server23 'hostname; uptime; ls /var | wc -l';
 1188  2009-04-07 08:31:47 history | tail -n3
pux@onkelpeter:~$ 
Man kann auch einen bereits eingegebenen Befehl selektiv wiederholen, mittels Ausrufezeichen:
pux@onkelpeter:~$ !1186
ssh onkelpeter.de 'hostname; uptime; ls /var | wc -l';
onkelpeter.de
 08:34:24 up 22 days,  9:18,  0 users,  load average: 10.83, 9.87, 9.54
17
pux@onkelpeter:~$ !-3
history | tail -n2
 1191  2009-04-07 08:34:39 ssh onkelpeter.de 'hostname; uptime; ls /var | wc -l';
 1192  2009-04-07 08:34:44 history | tail -n2
pux@onkelpeter:~$
Mit einem Minus wird umgekehrt gezählt (-3 ist dabei der drittletzte Befehl). Man kann die Historie auch durchsuchen. Dazu aber mehr unter Shortcuts.

Shortcuts

Um in der Bash schnell zu arbeiten gibt es wichtige Tastenkombinationen und Shortcuts.
Historie
Die Historie kann man mittels [Strg] + [R] durchsuchen. Man drückt dazu die Tastenkombination und gibt ein zu suchendes Wort ein. Der erste zutreffende Befehl wird daraufhin angezeigt. Erneutes drücken der Tastenkombination bringt einem zum 2. Ergebnis etc. Will man den Befehl Editieren, drückt man [ESC] oder eine Pfeiltaste nach links oder rechts, zum direkten Abschicken [Enter].

Etwas abbrechen
Um einen Befehl abzubrechen reicht in der Regel das drücken von [Strg] + [C].

Eine Verbindung "Kappen"
Wenn man per ssh auf einem System eingeloggt ist und dieses nichtmehr reagiert, kann man sich mittels [~] + [.] davon deconnecten.

Historie Scrollen
Um den letzten Befehl zu wiederholen, kann man mit den Pfeiltasten (hoch/runter) durch die Historie "Scrollen".

Wörter "bearbeiten"
Für schnelleres Arbeiten ist es hin und wieder erforderlich, ganze Wörter zu überspringen. Wer nur ls /home benutzt, für den macht so etwas keinen Sinn, aber wer so einen Befehl benutzt for i in `seq 1 800`; do ./interface.pl -m add_servicedowntime --Service Backup-onkelpeter.de --Begin '03/04/2009 17:00' --End '06/04/2009 10:00' --Comment 'Backups laufen amok' -c; echo $i ; done; sieht schnell, dass mit den Pfeiltasten nach links oder rechts bewegen länger dauern kann ;-). Deswegen kann man örter überspringen. [Alt] + [F] springt ein Wort nach rechts, [Alt] + [B] springt ein Wort nach links. Hin und wieder (in Terminals auf X-Servern z.B.) öffnen sich dann mit Alt und B z.B. das Kontextmenü "Bearbeiten". In solch einem Fall noch Shif"t mitücken": [Shift] + [Alt] + [F] / [Shift] + [Alt] + [B]
Evtl. funktioniert auch ein [STRG] + [F]/[STRG] + [B] (Cursortaste links bzw. rechts)

An Anfang/Ende springen
Um an den Anfang einer Befehlszeile zu springen benutzt man [Strg] + [A] um zum Ende zu gelangen [Strg] + [E]. Das funktioniert eigentlich immer, zumindest noch eher als [Pos1] und [Ende] ;-).

Wörter löschen
Mit [Alt] + [D] kann man ein Wort rechts vom Cursor löschen (auch hier, die Shifttaste mitbenutzen, falls ein Kontextmenü aufgeht...)

Vor/nach Cursorpos. löschen
[STRG] + [U] löscht alles vor der Cursorpos., also links davon. [STRG] + [K] löscht alles nach der Cursorpos., also rechts davon.

Buchstaben "ändern"
[Alt] + [C] Macht an der Stelle, an der der Cursor gerade ist einen Buchstaben gross und springt zum nächsten Wort (das mit der Shifttaste lasse ich ab hier weg, OK?).

Zeile leeren
[Alt] + [N] Leert die Zeile und schreibt einen ":".

Bildschirminhalt Scrollen
Den Inhalt des Bildschirms kann man mit [Shift] + [Bild hoch]/[Bild runter] hoch bzw. runter scrollen.

Solche Shortcuts gibt es noch massig, zu finden und definieren in der Datei /etc/inputrc

Login-Prompt

Das Loginprompt kann man auch ändern, wie eigentlich alles. Die Variable der Stunde ist PS1:
pux@onkelpeter:~$ echo $PS1
\u@\h:\w\$
Das "u" steht für username, das "h" für host und das "w" für den aktuellen Pfad. Wie schnell man daändern kann? Guggst du hier:
pux@onkelpeter:~$ echo $PS1
\u@\h:\w\$
pux@onkelpeter:~$ PS1="\u ist auf \h eingeloggt und macht im pfad \w rum..."
pux ist auf pux eingeloggt und macht im pfad ~ rum...ls
bin          Desktop                          ich.jpeg                 konzept.jpeg         nfs              pimp          smsbuch.txt            temp                      verdrahtung.pdf
bin_new      dp                               interfaces               liste                onkelpeter.de    praes.tar.gz  sq22                   testdatei                 xen
pux ist auf pux eingeloggt und macht im pfad ~ rum...cd /
pux ist auf pux eingeloggt und macht im pfad / rum...cd /home/
pux ist auf pux eingeloggt und macht im pfad /home rum...
pux ist auf pux eingeloggt und macht im pfad /home rum...PS1="\u@\h:\w"
pux@onkelpeter:/home
Auch hier: in der .bashrc/.bash_profile zu definierender Kram...

Farben

Man kann das Prompt (wie jede echo-Ausgabe übrigens auch) schön bunt machen. Dies geht mit den Farbencodes der Bash. Definiert werden diese so hier:
echo -e "\033[1;31mroter Text\033[0;0mschwarzer Text";
und alles wird rot bzw. schwarz.
Die Farben werden in Form von Zahlenwerten angegeben (siehe unten). Dabei werden bis zu vier Werte erwartet, die durch ein Semikolon voneinander getrennt werden. Mit den Zahlen werden spezielle Attribute (fett, blinkend, unterstrichen etc.), sowie die Farbe für den Vorder- und Hintergrund festgelegt. Eine Beonderheit betrifft gelb bzw. braun. Leuchtend helles braun wird nämlich als leuchtendes gelb dargestellt. Normales braun hingegen erscheint wie erwartet braun. Die Farbe ändert sich in Abängigkeit mit dem Attribut fett.
Code	Beschreibung
00	 Normale Video-Darstellung (z.B. weiss auf schwarz)
01	 Attribut fett
04	 Attribut unterstrichen
05	 Attribut blinkend
07	 Vorder- und Hintergrund vertauscht
22	 Normale Intensität wiederherstellen
30	 Vordergrund schwarz
31	 Vordergrund rot
32	 Vordergrund grün
33	 Vordergrund braun (bzw. gelb für fett)
34	 Vordergrund blau
35	 Vordergrund magenta
36	 Vordergrund cyan
37	 Vordregrund weiss
40	 Hintergrund schwarz
41	 Hintergrund rot
42	 Hintergrund grün
43	 Hintergrund braun
44	 Hintergrund blau
45	 Hintergrund magenta
46	 Hintergrund cyan
47	 Hintergrund weiss
49	 Voreingestellter Hintergrund

Alias-Definition

Um wiederkehrende Befehle schneller aufrufen zu können, kann man sich mittels dem Befehl alias einen Alias definieren. Was bereits definiert ist, gibt ein simples "alias" direkt aus:
pux@onkelpeter:~ alias
alias ..='cd ..'
alias ...='cd ../..'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -alFh --color=auto'
alias ls='ls --color=auto'
alias p='ping '
alias t='traceroute '
pux@onkelpeter:~ 
Aliase definiert man so hier (auch das kann man in seine .bashrc/.bash_profile packen):
alias p='ping '
alias ...='cd ../..'
Der "Befehl" p onkelpeter.de macht also in Wirklich ping onkelpeter.de. Oder ... ist dann ein Alias für cd ../...

Enviroment

Die Umgebungsvariabeln kann man sich mit dem Befehl env anzeigen lassen:
pux@onkelpeter:~ env
SSH_AGENT_PID=3199
SHELL=/bin/bash
TERM=xterm
WINDOW_MANAGER=/usr/bin/openbox
GTK_RC_FILES=/etc/gtk/gtkrc:/home/pux/.gtkrc-1.2-gnome2
WINDOWID=46157150
HISTFILESIZE=1000000
USER=pux
LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.svgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:
SSH_AUTH_SOCK=/tmp/ssh-KMXeFQ3198/agent.3198
GNOME_KEYRING_SOCKET=/tmp/keyring-GeRtyY/socket
SESSION_MANAGER=local/onkelpeter:/tmp/.ICE-unix/3010
USERNAME=pux
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/home/pux/bin
DESKTOP_SESSION=openbox-gnome
GDM_XSERVER_LOCATION=local
PWD=/home/pux
EDITOR=vim
LANG=de_DE.UTF-8
GNOME_KEYRING_PID=3009
FCEDIT=vim
GDM_LANG=de_DE.UTF-8
GDMSESSION=openbox-gnome
HISTCONTROL=ignoredups
HOME=/home/pux
SHLVL=1
GNOME_DESKTOP_SESSION_ID=openbox-session
LOGNAME=pux
CVS_RSH=ssh
XDG_DATA_DIRS=/usr/local/share/:/usr/share/:/usr/share/gdm/
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-gX9VCbarJc,guid=0093a972b5a3535a00b2ddec49d9c9d2
WINDOWPATH=7
DISPLAY=:0.0
HISTTIMEFORMAT=%Y-%m-%d %H:%M:%S 
COLORTERM=gnome-terminal
XAUTHORITY=/home/pux/.Xauthority
_=/usr/bin/env
OLDPWD=/home/pux/.ssh
pux@onkelpeter:~ 
In diesen Variabeln ist massig "Krimskrams" gespeichert, wie der letzbesuchte Pfad (OLDPWD), der Username, etc.

Variabeln setzen und ändern

Wie man eine Variable setzt, wurde bereits in Bashgrundlagen erklärt.

Spezial-Variabeln

Man findet in Shellscripten öfter "Variabeln", die recht kryptisch erscheinen aber zum debuggen sollte man wissen, was diese machen. Hier findet man eine kleine Übersicht:
Zeichenkettenoperatoren
Operator	Beispiel	Beschreibung
${name:n:m}	 ${s:1:3}${t:-2}	 liefert einen Teil des Inhalts der Variabeln. Gibt bei positivem n das Offset vom Anfang der Zeichenkette an, bei negativem n das Offset vom Ende der Zeichenkette, m ist die Anzahl der Zeichen. Ist n negativ, muss vor dem Minus ein leerzeichen stehen, um nicht mit ${name:-a} (siehe unten) verwechselt zu werden. m darf fehlen, liefert dann alle Zeichen ab Offset bis zum Ende der Zeichenkette. Die Beispiele liefern die Zeichen 2 bis 5 der Variabeln s und die letzten beiden Zeichen der Variablen t.
${name#a}	 ${drive#/dev}	 Entfernen des Anfangs: Prüft, ob der Ausdruck a auf den Anfang des Inhalts der Variablen passt und entfernt ihn. Wildcards sind erlaubt. Das Beispiel entfernt die Zeichenkette /dev einer Geräteausgabe wie /dev/hda.
${name##a}	 ${name##*/}	 wie #, entfernt jedoch alle Übereinstimmungen. Das Beispiel entfernt alle Zeichen vom Anfang bis einschliesslich des letzten Schrägstrichs und entspricht dem Befehl basename.
${name%a}	 ${dir%/*}	 wie #, prüft jedoch das Ende der Zeichenkette. Das Beispiel entspricht dirname und entfernt den Dateinamen nebst Slash einer Pfadangabe.
${name%%a}	 ${dir%/*}	 wie ##, prüft jedoch das Ende der Zeichenkette. Das Beispiel entfernt alle Zeichen bis auf den ersten Verzeichnisnamen einer relativen Pfadangabe.
${name/s/e}	 ${desktop/kde/gnome}${dir/*local*}	 Suchen/Ersetzen: Prüft ob der Ausdruck s im Inhalt der Variabeln vorkommt und ersetzt diesen Teil durch die Zeichenkette e. Wildcards sind erlaubt. Fehlt /e, wird die Übereinstimmung entfernt. Die Beispiele ersetzen kde durch gnome und entfernen die Pfade, die "local" enthalten.
${name//s/e}	 ${datei// /_}${datei//:}	 wie s/e, entfernt oder ersetzt jedoch alle Übereinstimmungen. Die Beispiele ersetzen Leerzeichen in Dateinamen durch Unterstriche und entfernen Doppelpunkte.
${name:-a}	 ${1:-/dev/null}	 Standartwert zurückgeben: Ist die Variable leer, wird stattdessen der hinter dem Operator angegebene Ausdruck eingesetzt. Liefert ansonsten den Inhalt einer Variabeln. Das Beispiel liefert /dev/null, falls kein Kommandozeilenparameter angegeben wurde.
${name:=a}	 ${configdir:=/etc}	 Standartwert zuweisen: Ist die Variable leer, wird ihr der hinter dem Operator angegebene Ausdruck zugewiesen und zurückgegeben. Liefert ansonsten den Inhalt der Variabeln. Funktioniert nicht mit Kommandozeilenparametern und Konstanten. Das Beispiel weist der Variabeln $configdir das Verzeichnis /etc zu, falls sie noch nicht gesetzt war.
${name:?s}	 ${1:?"Parameter fehlt"}	 Fehlermeldung: Ist die Variable leer, wird die Meldung hinter dem Operator ausgegeben und das Programm beendet. Liefert ansonsten den Inhalt der Variablen. Das Beispiel bricht das Programm mit einer Fehlermeldung ab, falls kein Kommandozeilenparameter angegeben wurde.
${name:+a}	 ${HOME}${datei:+/}${datei}	 Ist die Variable leer, ist das Ergebnis eine leere Zeichenkette. Liefert ansonsten den Ausdruck zurück, der hinter dem Operator angegeben ist. Das Beispiel liefert das Home-Verzeichnis des Benutzers, falls die Variable $datei leer ist, ansonsten wird ein Schrägstrich und der Dateinamen an den Pfad angeängt.

Variabeln

Variable	Kommentar
$?	 Rückgabewert des letzten Kommandos
$#	 Anzahl der übergebenen Argumente
$0	 Scriptname
$1	 Erster übergebener Parameter an ein Script
$2	 Zweiter übergebener Parameter an ein Script
$3	 Dritter übergebener Parameter an ein Script etc.
$!	 Enthält die Prozessnummer PID des zuletzt im Hintergrund gestarteten (und noch immer aktiven) Prozesses
$-	 Beinhaltet alle durch das eingebaute Kommando gesetzten Shellvariablen (den symbolischen Buchstaben, nicht den Variablennamen selbst!)
$_	 In Abhängigkeit vom letzten Vorgang steht entweder das letzte Argument des zuletzt ausgeführten Shellskripts (oder der zuletzt gerufenen Shell) drin oder, wenn die Mailboxen auf neue Nachrichten überprüft werden, der Name der aktuell betrachteten Datei.
${feld_var_name[2]}	 2. Feld des Arrays $feld_var_name

Ausgabe-Kanäle

Auf der Linux-Konsole gibt es 2 Ausgabekanäle. Den Standart-Ausgabe-Kanal und (stdout) und den Fehler-Ausgabekanal (stderr). Zudem gibt es noch den Standart-Eingabekanal (stdin). stdin ist das, was man eingibt. stdout ist das, was ein Programm oder ein Script/Befehl ausgibt. Auf stderr werden Fehler ausgegeben wie z.B. cronjob-Errors, Festplatten-Fehler, etc. stdin wird auch häufig mit einem "-" gekennzeichnet ("cat -" meint das gleiche wie einfach nur ein "cat").
Viele Befehle lesen von stdin und schreiben nach stdout (wenn sie denn etwas zu schreiben haben) bis man sie mit [Strg] + [D] dazu bringt, aufzuhören (in einer leeren Zeile drücken):
pux@onkelpeter:~$ cat
mooh
mooh
noch ein mooh
noch ein mooh
noch ein anderes mooh
noch ein anderes mooh
pux@onkelpeter:~$ grep mooh
text mit moh
text mit moo
text mit mooh
text mit mooh
text mit mh
pux@onkelpeter:~$ 

Ausgabe-Umleitungen

Will man nun aber eine Ausgabe umleiten, so macht man das mit "<" und ">". Dabei gilt erstmal, dass man die Ausgabe in eine Datei umleitet:
pux@onkelpeter:~$ cat > mooh
text
noch ein text
mehr text
pux@onkelpeter:~$ cat mooh 
text
noch ein text
mehr text
pux@onkelpeter:~$ 
Will man etwas an eine Datei anhängen, benutzt man ">>". Der Unterschied zu ">" sollte schnell klar sein:
pux@onkelpeter:~$ cat > mooh
test
mooh
pux@onkelpeter:~$ cat mooh 
test
mooh
pux@onkelpeter:~$ cat > mooh
noch ein test
pux@onkelpeter:~$ cat mooh 
noch ein test
pux@onkelpeter:~$ cat >> mooh
text anhängen
pux@onkelpeter:~$ cat mooh 
noch ein test
text anhängen
pux@onkelpeter:~$ cat > mooh
datei leeren und von vorne reinschreiben
pux@onkelpeter:~$ cat mooh 
datei leeren und von vorne reinschreiben
pux@onkelpeter:~$ 
Man kann auch aus Dateien (anstatt von stdin) lesen und auf stdout schreiben, was ein "cat mooh" letzendlich ja macht, aber das nur nebenbei erwähnt.
Will man stderr umleiten, kann man das so hier machen:
pux@onkelpeter:~$ cd mooh
bash: cd: mooh: Ist kein Verzeichnis
pux@onkelpeter:~$ cd mooh 2> error.txt
pux@onkelpeter:~$ cat error.txt 
bash: cd: mooh: Ist kein Verzeichnis
pux@onkelpeter:~$ 
Will man stdout und stderr umleiten, so geht das wie folgt:
pux@onkelpeter:~$ cd mooh 
bash: cd: mooh: Ist kein Verzeichnis
pux@onkelpeter:~$ cd mooh > ausgabe.txt 2>&1
pux@onkelpeter:~$ cat ausgabe.txt 
bash: cd: mooh: Ist kein Verzeichnis
pux@onkelpeter:~$ cd bin > ausgabe.txt 2>&1
pux@onkelpeter:~/bin$ cd ..
pux@onkelpeter:~$ cat ausgabe.txt 
pux@onkelpeter:~$ 
Nun gibt es noch die Möglichkeit, eine Eingabe aus einer Datei zu beziehen:
pux@onkelpeter:~$ cat > mooh
eine zeile
zwei zeilen
drei zeilen
pux@onkelpeter:~$ sort < mooh 
drei zeilen
eine zeile
zwei zeilen
pux@onkelpeter:~$ 
Und wie ">>" gibt es auch noch "<<":
pux@onkelpeter:~$ cat < mooh
> nun kann ich tippen 
> bis das wort MARKER alleine
> in einer zeile vorkommt.
> das alles wird nun in die datei mooh geschrieben.
> MARKER
pux@onkelpeter:~$ cat mooh 
nun kann ich tippen 
bis das wort MARKER alleine
in einer zeile vorkommt.
das alles wird nun in die datei mooh geschrieben.
pux@onkelpeter:~$ 

Pipes

Man kann nun aber die Ausgabe nicht nur in Dateien umleiten, sondern sie auch an einen Befehl "weitergeben". Das macht man mittels einer Pipe (|):
pux@onkelpeter:~$ cat mooh 
nun kann ich tippen 
bis das wort MARKER alleine
in einer zeile vorkommt.
das alles wird nun in die datei mooh geschrieben.
pux@onkelpeter:~$ cat mooh | sort
bis das wort MARKER alleine
das alles wird nun in die datei mooh geschrieben.
in einer zeile vorkommt.
nun kann ich tippen 
pux@onkelpeter:~$ 
Das Ganze kann man natürlich beliebig kombinieren und benutzen:
pux@onkelpeter:~$ cat < fertig.txt
> eine zeile
> noch ne zeile
> zeile drei
> MARKER
pux@onkelpeter:~$ cat fertig.txt 
      1 eine zeile
      1 noch ne zeile
      1 zeile drei
pux@onkelpeter:~$ 

Wenn (nicht) erfolgreich abgeschlossen, dann...

Man kann unter Linux angeben, was passiert, wenn ein Befehl erfolgreich verlaufen ist. Das macht man mittels dem doppelten Kaufmännischen und "&&":
pux@onkelpeter:~$ cd bin && echo "tut"
tut
pux@onkelpeter:~/bin$
Wenn man z.B. einen fsck laufen lässt und will, dass wenn dieser erfolgreich war (und nur dann) die Platte anschliessend gemounted wird. Oder aber genau das Gegenteil; Wenn der fsck nicht erfolgreich war, soll eine mail versendet werden. Nicht erfolgreich gibt man mit "||" (2 Pipes) an:
pux@onkelpeter:~$ cd mooh || echo "tut nicht"
bash: cd: mooh: Ist kein Verzeichnis
tut nicht
pux@onkelpeter:~$ 

Hintergrund, Vordergrund

Will man einen Befehl, ein Script oder was auch immer im Hintergrund laufen lassen, so startet man den Befehl mit einem "&" am Ende. Man kann sich seine im Hintergrund laufenden Prozesse mit dem Befehl "jobs" anzeigen lassen. Jobs, die im Fordergrund laufen, kann man mit [Strg] + [Z] stoppen und dann mit fg oder bg unter der Angabe der job-Nummer in den Fordergrund bzw. Hintergrund zurückholen/schieben:
pux@onkelpeter:~$ cat /dev/zero > /dev/null &
[1] 21577
pux@onkelpeter:~$ jobs
[1]+  Running                 cat /dev/zero > /dev/null &
pux@onkelpeter:~$ fg 1
cat /dev/zero > /dev/null
^Z
[1]+  Stopped                 cat /dev/zero > /dev/null
pux@onkelpeter:~$ bg 1
[1]+ cat /dev/zero > /dev/null &
pux@onkelpeter:~$ jobs
[1]+  Running                 cat /dev/zero > /dev/null &
pux@onkelpeter:~$ fg 1
cat /dev/zero > /dev/null
^C
pux@onkelpeter:~$ jobs
pux@onkelpeter:~$



  logo