bash - Die Bourne again shell
Inhaltsverzeichnis
- bash - Die Bourne again shell
Vorwort
bash ist die GNU/Linux-Standard-Shell. Sie wurde vom GNU-Projekt entwickelt. Sie ist abwärts kompatibel zur sh, der ursprünglichen Unix Shell. Shellskripte sollte man immer in sh bzw Bash schreiben und nicht in eine der zahlreichen anderen Shellvarianten (ksh, (t)csh).
Man kann damit nicht nur (wie unter DOS mit Batches) einfache Abläufe automatisieren, sondern richtige Programme erstellen, da diese Shell viel mächtiger ist und auch die UNIX-Befehle viel besser auf "Kooperation" nach dem Baukastensystem eingestellt sind.
Ab Version 2.04 bietet die bash eine programmierbare automatische Eingabe-Vervollständigung, siehe dazu den Bericht auf ProLinux: Die Tabulatortaste (TAB) ergänzt oft das angefangene Wort: Ist es eindeutig, reicht ein TAB, sonst listet ein zweites TAB die Alternativen auf. Ein Pieps zeigt an, dass keine Ergänzungsmöglichkeit gefunden wurde. Damit können Dateienamen, Kommandos, aber teilweise auch Parameter in Kommandos komfortabel und gedächtnisplatzschonend ergänzt werden.
Versionstand
Aktuell ist 4.0 erschienen, siehe auch http://www.pro-linux.de/news/2009/13849.html
Start
Der Kommandozeileninterpreter führt beim Start nacheinander die folgenden Dateien aus, in denen systemweite oder benutzer-spezielle Einstellungen vorgenommen werden können, die bei jedem Anmelden an das System vorgenommen werden:
- ~/.bash_profile
- ~/.bash_login
- ~/.profile
Von bash wird aufgerufen: /etc/profile, dann ~/.bash_profile. Falls .bashrc aufgerufen wird, dann deswegen, weil ein Aufruf von ~/.bashrc im script ~/.bash_profile drinsteht.
In ~/.bashrc kann der Benutzer alle seine Abkürzungen und bevorzugten Einstellungen vornehmen.
Die Eingabeaufforderung kann angegeben werden durch die env-Variable PS1:
export PS1="\u \w #"
Besondere Bedeutung haben die Umschreibungen:
- \h : Host name
- \H : Host name inklusive Domain
- \d : Datum
- \t : time Zeit
- \u : User Benutzerkennung
- \w : Working directory, aktuelles Arbeitsverzeichnis
- \l : Terminalname, zum Beispiel tty1
- \# : Eingabezeilennummer
- \\ : Das Zeichen "\"
Einen farbigen Prompt erreicht man durch die entsprechenden Escape-Codes. Beispiel:
export PS1="\[\033[1;73m\][\$(date +%H:%M)]\[\033[1;36m\][\[\033[1;34m\]\u\[\033[1;33m\]@\[\033[1;32m\]\h:\[\033[1;35m\]\w\[\033[1;36m\]]\[\033[1;31m\]\\$\[\033[0m\] "
Dies ergibt einen Prompt mit hellrotem Benutzernamen, grünem Hostnamen und orangem Arbeitsverzeichnis.
von bash benutzte Umgebungsvariablen
bash benutzt die folgenden env-Variablen
- PATH=.:~/bin:/bin:/sbin:/usr/bin:/usr/sbin Suchpfad für externe Kommandos (Programme)
- HOME Heimatverzeichnis aus /etc/passwd
- MAILCHECK
- TMOUT=n Nach n Sekunden die shell automatisch beenden
- FIGORE=r:z Die Dateinamenerweiterungen bei Tab nicht beachten
- PWD Das aktuelle Verzeichnis
- OLDPWD Das letzte aktuelle Verzeichnis
- $? Numerischer Wert der vom zuletzt aufgerufenen Kommando exit(2) zurückgegeben wurde.
- $1 $2 Aufruf-Parameter
- $# Anzahl der Aufruf-Parameter
- $$ Prozessid der Shell. (Nützlich z.B. für eindeutige temporäre Dateinamen)
Hinweis: Wenn ein Script mit vorangestellten ". " (oder "source ") aufgerufen wird, dann wird keine neue Ausprägung von bash das Script ausführen, sondern die Eingabebash direkt. Nur so können Variablen von einem Script übernommen werden.
Wie Befehle eingegeben werden können
ls -R | grep tg | more
Durch den senkrechten Strich | wird die Ausgabe eines Programms (Prozess) in das nachfolgende Programm umgeleitet. 3 Programme werden dadurch gestartet : ls zeigt das Inhaltsverzeichnis an, grep sucht in der Ausgabe von ls nach dem Textstring "tg" und gibt nur die Zeilen weiter, die tg enthalten, more zeigt dann alles seitenweise an.
cd /tmp ; rm -f * ; ist ein "logischer Zeilenwechsel". Hier stehen also 2 Kommandos in einer Zeile.
ls -l >xxlst durch das Zeichen "Größer als" > wird die Ausgabe umgeleitet, hier im Beispiel in eine Datei.
ls >> xx2 Doppelter Pfeil: Anhängen an Datei
cp /x /y 2>error.log Nicht die Standardausgabe, sondern Kanal 2 (Fehlerausgabe) wird umgeleitet
for zuz in *.c ; do echo $zuz $zuz ; done Wiederhole mittleren Teil echo $zuz $zuz
find / -name "*.dat" >xx & ls -l > xxl & ist ebenfalls ein logischer Zeilenwechsel, startet den Prozess jedoch im Hintergrund, d.h. das Ende des Prozesses (hier find) wird nicht abgewartet sondern das nächste Kommando (hier ls) ausgeführt.
find / -name "*.dat" >xx & Starten im Hintergrund (kein 2. Kommando).
mount /dev/cdrom && cp /media/cdrom/* /backup : Das Copy-Kommando (cp) wird nur ausgeführt, wenn mount den Exit-Code 0 liefert ("kein Fehler")
cd /works || mkdir /works mkdir wird nur ausgeführt wenn cd nicht den Exit-Code 0 liefert ("Fehler")
( liste ) Die Befehle "liste" werden in einer Sub-shell ausgeführt.
- select ... : Kenne ich nicht, siehe man bash
Mit $ beginnen Variablennamen:
- $$ : Prozessid
- $1 .. $9 : Parameter der Kommandodatei
- $# : Anzahl der Parameter
- $NNNN : Einige besondere Namen , Siehe man bash
- name=string text : Zuweisung von Environment-Variablen. Wenn die Variable aus der Datei .bashrc in die gestartete shell übernommen werden soll, dann muß auch export davorstehen.
<<WORT : HERE-Dokument: Alle Zeilen zwischen WORT und einer späteren Zeile mit WORT wird in die Eingabe (stdin) des Programmes geleitet. Siehe Beispiele.
Dateien werden von bash ausgeführt, wenn in der ersten Zeile steht:
Steuercodes (Ctrl-)
- Control-c : Beenden des letzten Vordergrundprogramms.
- Control-d : Beendet das Lesen von der Standardeingabe (End of File).
Control-v : Erlaubt die Eingabe von Control-Zeichen als Programmargumente. Bsp: qqmain VHVH
- Control-z : Schickt des laufende Programm in den Hintergrund. Mit fg nummer kann es wieder in den Vordergrund geholt werden.
- Control-a : Geht ans ende der aktuellen Zeile
- Control-e : Geht an den Anfang der aktuellen Zeile
Eingebaute bash-Befehle
Hilfe über die eingebauten bash-Befehle gibt es mit help
- alias name=text
- bg
- bind
- break
- builtin
- case
- cd
Standardverzeichnis wechseln. siehe #bsp_cd
- command
- continue
- declare
declare -x PATH
- Damit wird die gesetzte Env-Variable PATH in die aufrufende bash exportiert. Muß in den Einstellungsdateien angegeben werden.
- dirs - Diese Kommando gibt den Namen des Arbeitsverzeichnisses zurück. pwd gibt den absoluten Pfad zurück, dirs gibt, wenn möglich den relativen Pfad zurück:
Eingabe:
cd echo `pwd` `dirs` cd /home/hjh/home/cc echo `pwd` `dirs` cd /tmp echo `pwd` `dirs`
Anzeige:
hjh ~ : echo `pwd` `dirs` /home/hjh ~ hjh ~ : cd /home/hjh/home/cc hjh ~/home/cc : echo `pwd` `dirs` /home/hjh/home/cc ~/home/cc hjh ~/home/cc : cd /tmp hjh /tmp : echo `pwd` `dirs` /tmp /tmp
- disown
- echo Anzeigen / Ausgeben von Text
echo Kommando ist abgearbeitet
- Zeigt den Text an.
- enable
- eval
- exec
- exit
- export - macht aus einer Shellvariable eine Umgebungsvariable d.h. das sie mit in die Subshell(s) übernommen wird. Ein Beispiel:
lenny:~# VAR=wert lenny:~# echo $VAR wert lenny:~# bash lenny:~# echo $VAR lenny:~# exit lenny:~# echo $VAR wert lenny:~# export VAR=wert lenny:~# echo $VAR wert lenny:~# bash lenny:~# echo $VAR wert lenny:~#
- false
- fc
- fg fg 1 holt den Prozeß 1, der durch Ctrl-Z in den Hintergrund, (engl. Background) geschickt wurde, wieder in den Vordergrund (engl. foreground).
- for
for i in *.c; do base=basename $i .c ; rm $base.o ; done Löscht Object-Dateien, von denen Quellen existieren
- function - Unterprogramme / Unter-Scripts im Shell-Script. Siehe #bsp_function
- getopts
- hash
- help Hilfe zu den hier beschriebenen Kommandos
- history Zeigt alle bisher eingegeben Befehlszeilen an.
- if Startet ein Kette von Befehlen und fragt den letzten Rückgabewert ab.
Hinweis : Normalerweise stehen jedes der Wörter if then else fi in eigenen Zeile. Man kann aber auch den "logische Zeilenwechsel" ; verwenden.
jobs - Nach dem Starten eines Prozesses im Hintergrund ( prozessname & ) oder nach dem Stoppen eines Prozesses mit Strg+Z wird eine job-id vergeben. Das Kommando jobs zeigt die momentan vergebenen job-ids an.
- kill sendet ein Signal an einen Prozess. Eine Liste der Signale gibt es mit kill -l. kill -9 PID bzw. kill -SIGKILL bricht einen Prozess ab, der nicht mehr auf Eingaben reagiert ("Zombie-Prozess). Standardmäßig ( kill PID ) wird das Signal SIGTERM (15) gesendet, was den Prozess auffordert, sich ordnungsgemäß zu beenden (exit 0).
- let - mit let sind arithmetische Rechenoperationen möglich.
- local local name=text setzt eine env-Variable
- logout Beendet bash. Damit beendet ein Benutzer seine Anmeldung an seiner Konsole. Geht auch durch Dateiende ([Ctrl-d])
- popd
- pushd
- pwd Print Working directory. Zeigt das aktuelle Arbeitsverzeichnis an.
- read
read -p Welche_Datei_:
- Läßt den Benutzer etwas eingeben. Das steht danach in der Variablen $REPLY
read -p Welche_Datei_: INPUT
- Läßt den Benutzer etwas eingeben. Das steht danach in der Variablen $INPUT
- readonly
- return
- set
- shift
- shopt
- source
- suspend
- test Test gibt als Rückgabewert true (1) zurück, wenn wahr ist:
- test -e dateiname ; Die Datei existiert test -r dateiname ; Die Datei existiert und ist lesbar test -w dateiname ; Die Datei existiert und ist schreibbar test -x dateiname ; Die Datei existiert und ist ausführbar test dateiname1 -nt dateiname2 ; Die Datei1 ist neuer als Datei2 test $1 = xx.cpp ; Die Zeichenketten links und rechts gleich sind.
- time Zeigt an, wieviel Zeit ein Kommando verbraucht,
- Beispiel: time lnk cpylines
- times
- trap
- true ist immer wahr (gibt 1 zurück). Damit kann etwas immer wiederholt werden.
- Beispiel : while true ; do echo zzz ; done ;
- type Zeigt an, woher ein Befehl kommt.
- hjh@hetol:~/home/cc/util$ type true true is a shell builtin hjh@hetol:~/home/cc/util$ type echo echo is a shell builtin hjh@hetol:~/home/cc/util$ type vim vim is /usr/bin/vim hjh@hetol:~/home/cc/util$
- typeset
- ulimit
- umask - liefert die aktuell gesetzte umask (z. B. 0022)
- unalias
- unset - entfernt eine Variable komplett.
- until
- while : Beispiel, wie ein Kommando ( free ) alle 3 Sekunden wiederholt werden kann:
while true ; do clear ; free ; sleep 3s ; done ;
- wait : wartet bis der Process mit der angegeben Nummer beendet ist.
Angabe von Dateinamen als Aufruf-Parameter
Programme werden bevorzugt aufgerufen mit Dateinamen. Die Programme selbst erhalten Argumente. Die shell, hier bash, erweitern Gruppen zu einer Liste einzelner Dateinamen. Nachfolgend der Aufruf eines Programms qqmain
qqmain abc.c : Wenn keine der Sonderzeichen enthalten sind wird der Parameter so übergeben, wie er eingegeben wurde.
qqmain *ser*.c : Alle Dateinamen (des aktuellen Arbeitsverzeichnisses) die "ser" enthalten und mit ".c" aufhören, werden übergeben.
qqmain qq[acf-m]*.cpp : in [] sind Buchstabengruppen enthalten, die einzeln aufgeführt sind wie 'a' und 'c' oder in einem Bereich von 'f' bis 'm' liegen.
- qqmain [!q][!q]*.cpp ! ist die Negierung eines Bereichs.
Der Kommandozeileneditor
Ctrl-R l s Sucht rückwärts im Kommandozeilenspeicher (engl.: history) nach "ls"
Esc < Anfang des Kommandozeilenspeichers
Esc > Ende des Kommandozeilenspeichers
Den Kommandozeileneditor gibt es in zwei Ausführungen :
set -o vi : wie der Editor vi
set -o emacs : wie der Editor emacs
wie vi
wie emacs
Pfeiltasten bewegen die Einfügemarke (engl Cursor)
Esc-F positioniere Wortende
Esc-B positioniere Wortanfang
Ctrl-E positioniere Zeilenende
Ctrl-A positioniere Zeilenanfang
Ctrl-K Lösche bis Zeilenende
Ctrl-Y Einfügen aus Löschspeicher
Tab Dateinamen automatisch erweitern. Geht beim Befehl und auch bei den Argumenten.
Links
Programmierung der Bourne Again Shell Einstieg in Landessprache mit Beispielen (Linux Fibel)
UNIX Shell-Programmierung von Kristian Köhntopp
Advanced Shell Scripting Guide (englisch) ist sehr ausführlich und hat zu allem Beispiele.
/bin/bash Treffpunkt für Linux-Shelluser.
Beispiele für bash - scripts
- So wird der Suchpfad eines Benutzers erweitert :
In ~/.bashrc :
PATH=${PATH}:/home/hjh/home/cc/linux:/home/hjh/home/cc/bin export PATH
- Hinweis: viele shell - scripts sind in /bin oder in /usr/sbin.
Zum Anzeigen eingeben:
grep "#\!/bin/sh" *
Beispiel HERE-Dokument: Variablen werden expandiert:
cat >/tmp/killer <<EOS ; chmod +x /tmp/killer ; /tmp/killer echo "Wir beenden die ausführende Shell!" kill -9 $$ EOS
Ausgabe von grep kill /tmp/killer liefert:
kill -9 6893
Beispiel HERE-Dokument: Variablen werden nicht expandiert:
cat >/home/bin/my_profile <<"EOS" ; chmod +x /home/bin/my_profile alias "my_pid=echo 'Aktuelle Prozess-Id: ' $$" EOS
Ausgabe von grep alias /home/bin/my_profile liefert:
alias "my_pid=echo 'Aktuelle Prozess-Id: ' $$"
Tipps & Tricks
Eine kleine Einführung in die GnuTextUtilities: sed, tr, cut, ...
Mit script kann ich die Ein- und Ausgabe mitschneiden um sie mit später replay anzusehen (siehe BildschirmFoto).
Wie erstelle ich ein ShellScript und mache es ausführbar?
Wie kann ich (z.B. in einem Skript) einen TonAusgeben lassen?
Wie kriege ich einen ShellVariablenTeil zu fassen?
Wie kann ich selber Meldungen ins SysLog schreiben?
- Shell-Scripts debuggen
Wenn man Shellscripts schreibt und diese nicht richtig funktionieren, ist die Fehlersuche meist sehr mühsam. Einfach am Anfang des Scripts folgenden Befehl einfügen, dann wird jede Zeile angezeigt bevor sie abgearbeitet wird: set -vx
- Piepston erzeugen
Wenn man in einem Script einen Piepston ausgeben möchte, kann man dies mit folgender Anweisung erreichen: echo -e "\a"
M-., M-_ fügt das Argument des letzten Befehls ein.
Mit C-r kann man in der History rückwärts nach Befehlen suchen.
Mit !-1:gs/falsch/richtig ersetzt (s) man im letzten Befehl (!-1) falsch durch richtig, und macht dass für alle Vorkommen von falsch, also global (g).
Lösungen für "Argument list too long" finden sich hier.
- Den aktuellen Pfad eines Scriptes bekommt man mit:
DIR=$(cd $(dirname $0) 2>/dev/null && pwd)
Fragen und Antworten
Frage: ich muss ein Skript programmieren, das unter bash aber auch unter sh (Solaris) läuft. Wo bekomme ich ein sh für Linux ? -- ThomasKalka 2002-10-22 14:52:14
welche sh? sh sagt eigentlich nur aus, das sie POSIX kompatibel ist. Abstufungen gibt es viele, ash, bash, csh, tcsh, zsh. -- BastianBlank 2002-10-22 16:13:29
- Die (t)csh ist nicht zur sh kompatibel
Unter den meisten Linuxdistributionen ist /bin/sh ein Link auf /bin/bash. Die Bash ist (aufwärts-)kompatibel zur sh. D.h die bash unterstützt alle Features der sh - aber nicht umgekehrt. Wenn Du Dein Skript einfach mit #!/bin/sh beginnst und nur die Standardfeatures verwendest, sollte das ganze auch auf der sh laufen. Zu den Standardfeatures würde ich mal die sh man page besuchen.
Danke. Würde gerne aber unter Linux testen und nicht unter Solaris. Wäre schön, wenn jemand etwas kennt. Sollen wir eine Seite GesuchteSoftware einrichten ? --ThomasKalka
wenn du POSIXLY_CORRECT setzt, müsste es eigentlich passen -- RonnyBuchmann 2002-11-18 16:13:57
Das Debian-Paket ash enthält die /bin/sh aus NetBSD. Das ist tatsächlich eine sh und keine bash. -- BennySiegert 2002-11-18 17:31:14
Ansonsten gibt es natürlich auch die bash für Solaris, dürfte im Endeffekt einfacher sein wenn Du das installieren darfst (Die "plain" Shell kann nicht sonderlich viel). Findest Du bspw. unter http://www.sunfreeware.com
Die "ash" (oder auch "dash") ist POSIX kompatibel und hat fast keine Erweiterungen. Wenn etwas also mit ash läuft, sollten die meisten Bourne Shells damit zurecht kommen. Außerdem lädt die "ash" wesentlich schneller, als die "bash". -- AndreasFoerster 2006-07-01 14:51:11
Frage: wie verhindere ich unkorrekte Umbrüche bei farbigen Prompts?
- Das vorzeitige Umbrechen und das falsche Zeilenspringen wenn bei Umbruch am Zeilenanfang Zeichen mit Backspace gelöscht werden liegt daran das die Bash die ANSI-Sequenzen im Prompt als sichtbare Zeichen mitzählt. Damit glaubt die Bash weniger Zeichen vom Zeilenende entfernt zu sein als sie wirklich ist und bricht vorzeitig um. Lösung ist das Klammern aller nicht mitzuzählender Zeichen im Prompt (also der ANSI-Sequenzen für die Farben) mit "\[" vor und "\]" hinter dem nicht mitzuzählendem Teilstring.