Die Zeichenkombination ./ – also ein Punkt gefolgt von einem Schrägstrich (auch bekannt als Slash) – wird häufig vor Linux-Befehlen verwendet. Besonders Linux-Einsteiger stoßen auf diese Kombination, wenn es darum geht, ein Programm oder ein Skript auszuführen, das im aktuellen Verzeichnis einer Shell liegt. Was verbirgt sich hinter diesem scheinbar kryptischen Kommando, und muss man es immer eingeben? Ich versuche, den Dschungel ein wenig zu lüften.
Bevor ich zum ./ komme, muss ich ein wenig ausholen und ein paar Grundlagen in Bezug auf die Linux-Shell und die Umgebungsvariable $PATH erklären. Eine Shell ist ein Programm, das eine textbasierte Benutzerschnittstelle bereitstellt, in die der Benutzer Befehle eingeben kann, die dann von der Shell ausgeführt werden.
Bei der Ausführung eines Befehls in einem Linux-System wird entweder ein in der Shell fest eingebautes Kommando ausgeführt oder ein ausführbares Programm oder Skript, das sich irgendwo auf der Festplatte befindet. Zu den eingebauten Befehlen gehören beispielsweise cd, echo, kill oder alias. Diese Befehle sind fest in der Shell integriert, sodass beim Aufruf dieser Befehle kein externes Programm ausgeführt wird. Im Gegensatz dazu stehen ausführbare Programme wie mv, less, gedit oder firefox, deren ausführbare Dateien oft im Verzeichnis /usr/bin liegen.
Gibt man nun einen Befehl in eine Shell ein, prüft die Shell zunächst, ob dieser Befehl eingebaut ist. Erkennt die Shell einen externen Befehl, durchsucht sie den Pfad (über die Variable $PATH) nach einer ausführbaren Datei mit demselben Namen und führt diese aus, wenn die Suche erfolgreich war. Über…
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
…könnt ihr euch den aktuellen Suchpfad anzeigen lassen. In jedem dieser Verzeichnisse sucht die Shell nach ausführbaren Dateien. Die Reihenfolge der Einträge ist dabei von Bedeutung. Wird nach foo gesucht und im Verzeichnis /usr/local/bin das Skript gefunden, dann wird /usr/local/bin/foo ausgeführt, auch wenn es in /usr/bin noch eine Datei namens foo gibt. Diesen Punkt sollte man nicht aus dem Gedächtnis verlieren.
Skripte in einem Verzeichnis ausführen
Nun kann ich den Bogen zum ./ wieder schließen. Angenommen, ihr wollt ein Skript oder ein Programm ausführen. Als Beispiel nehme ich ein Skript namens beispiel.sh im Verzeichnis ~/tmp in eurem Home-Verzeichnis. Öffnet dazu ein Terminal, geht in das Verzeichnis, in dem sich das Skript befindet, und versucht, es aufzurufen…
otto@computer:~$ cd tmp
otto@computer:~/tmp$ beispiel.sh
beispiel.sh: command not found
otto@computer:~/tmp$ ls -al beispiel.sh
-rwxr-xr-x 1 otto otto 61 2010-02-03 15:28 beispiel.sh
Wie ihr seht, wird das Skript nicht gefunden, obwohl ich mich im richtigen Verzeichnis befinde, das Skript da ist und die Berechtigungen stimmen. Warum klappt das also nicht? Die Lösung liegt im vorhin beschriebenen $PATH. Zur Erinnerung gebe ich ihn nochmal aus…
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
Die Shell erkennt schnell, dass beispiel.sh kein eingebauter Shell-Befehl ist, daher durchsucht sie den Pfad. Auch hier wird sie jedoch nicht fündig. In den Verzeichnissen, die im $PATH enthalten sind, wird keine Datei namens beispiel.sh gefunden, weshalb die Shell „command not found“ ausgibt. Was ist also los? Der Grund ist einfach: Der $PATH enthält nie das aktuelle Verzeichnis, in dem man sich befindet. Um also mein Skript beispiel.sh auszuführen, müsste ich den vollständigen Pfad angeben…
otto@computer:~$ cd tmp
otto@computer:~/tmp$ /home/otto/tmp/beispiel.sh
Dies ist nur ein Beispiel für ein Skript.
otto@computer:~/tmp$ $HOME/tmp/beispiel.sh
Dies ist nur ein Beispiel für ein Skript.
otto@computer:~/tmp$ ~/tmp/beispiel.sh
Dies ist nur ein Beispiel für ein Skript.
Wie ihr seht, gibt es zahlreiche Varianten, den Pfad zur Datei anzugeben. Das Tippen dabei ist jedoch aufwändig, weshalb es Abkürzungen gibt, die einem die Arbeit erleichtern. Die kürzeste Möglichkeit, einen Pfad zum aktuellen Verzeichnis anzugeben, ist der Punkt. Der Punkt steht für das aktuelle Verzeichnis, sodass zum Ausführen von beispiel.sh einfach ./ als Pfadangabe ausreicht…
otto@computer:~$ cd tmp
otto@computer:~/tmp$ ./beispiel.sh
Dies ist nur ein Beispiel für ein Skript.
Warum ist das aktuelle Verzeichnis nicht im Pfad?
Ihr stellt euch nun möglicherweise die Frage, warum das aktuelle Verzeichnis nicht im Pfad enthalten ist. Man würde sich doch einiges an Tipparbeit und vor allem Verwirrung ersparen. Der Grund ist einfach: Sicherheit! Stellt euch vor, jemand gibt euch ein paar Daten, die ihr via Shell irgendwohin verschieben sollt. In den Daten befindet sich jedoch eine unscheinbare Datei namens mv mit folgendem Inhalt…
#!/bin/bash
rm -rf $HOME
Geht ihr nun in das Verzeichnis und gebt den Befehl…
otto@computer:~$ cd ~/daten
otto@computer:~/daten$ mv beispiel.* /wohin/auch/immer
…ein, dann würde – solange das aktuelle Verzeichnis vor /usr/bin im $PATH steht – das im Verzeichnis enthaltene mv-Skript ausgeführt werden und nicht das /usr/bin/mv. Das Ergebnis? Euer gesamtes Home-Verzeichnis würde kommentarlos und auf einen Schlag gelöscht werden. Wäre das aktuelle Verzeichnis im $PATH vor den Systempfaden wie /usr/bin und Co. eingetragen, könnte man ohne Weiteres schadhafter Software oder sogar Schadcode unterjubeln.
Kann ich das aktuelle Verzeichnis wirklich nicht in den $PATH aufnehmen?
Falls euch der Ausschluss des aktuellen Verzeichnisses wirklich stört, ist es problemlos möglich, das aktuelle Verzeichnis in den $PATH aufzunehmen. Ob es sinnvoll ist, darüber möchte ich aufgrund des oben genannten Negativbeispiels nicht weiter spekulieren. Den Pfad könnt ihr über einen Eintrag in der Datei ~/.profile in eurem Home-Verzeichnis anpassen. Fügt ihr am Ende der Datei beispielsweise diesen Eintrag hinzu…
PATH="$PATH:."
…und startet eine neue Shell, sieht euer $PATH schließlich so aus.
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:.
Am Ende steht der . für das aktuelle Verzeichnis. Mit…
otto@computer:~$ cd tmp
otto@computer:~/tmp$ beispiel.sh
Dies ist nur ein Beispiel für ein Skript.
…könnt ihr dann das Beispiel-Skript ausführen. Ihr seht, kein ./ mehr nötig. Steht der Punkt am Ende des Pfades, so besteht auch keine Gefahr, dass der oben beschriebene Trick funktioniert, aber es gibt einen sicheren Weg, eigene Skripte ohne Pfadangaben auszuführen.
Die Verzeichnisse ~/bin und /usr/local/bin
Ihr könnt in eurem Home-Verzeichnis einen Ordner namens ~/bin anlegen. Beim Starten einer Shell wird automatisch geprüft, ob dieser Ordner existiert. Wird er gefunden, wird er automatisch in den $PATH aufgenommen. Dies funktioniert über den folgenden Abschnitt…
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi
…in der Datei ~/.profile, die beim Starten einer Shell ausgeführt wird. Wenn ihr euch den $PATH nun anseht, wird er folgendermaßen aussehen…
$ echo $PATH
/home/otto/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
Der Ordner /home/otto/bin steht nun an erster Stelle, und Skripte, die ihr dort ablegt, werden automatisch gefunden. Wenn ihr wollt, dass euer Skript oder kleines Programm von allen Benutzern des Systems verwendet wird, solltet ihr es nach /usr/local/bin kopieren oder dort verlinken. Dieses Verzeichnis befindet sich ebenfalls immer im $PATH, und die Paketverwaltung legt dort keine Dateien ab. Es ist also euer persönliches Verzeichnis.





Schreibe einen Kommentar