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.

Abonnieren
Benachrichtigungen:
guest
27 Kommentare
älteste
neuste
Inline Feedbacks
Zeige alle Kommentare
zerwas

Schöne Zusammenfassung für Einsteiger. 🙂 Werde ich nächstes mal jemandem direkt verlinken, wenn er nach ./ fragt.

Noch eine Frage dazu, da ich das Thema letzt erst hatte: Wie „standardkonform“ ist es, z.B. heruntergeladene Java-Programme oder sonstiges nach ~/bin anstatt nach /opt zu verfrachten? Will heißen: Ist ~/bin distributionsübergreifend?

bernd

schöner Artikel, Danke

Julian

ls, echo und kill sind in keine Shell integriert sondern liegen in /bin.

Perry3D

Noch eine kleine Ergänzung: ~/.profile stimmt glaub ich nur bei einer login-shell. Ansonsten ist es ~/.bashrc.

Nachzulesen in der manpage von bash.

Luca

Du hättest vielleicht noch auf den Selektor .. eingehen sollen für den übergeordneten Pfad. Den man übrigens auch mehrfach kombinieren kann, um mit ../../../beispiel.sh zum Beispiel das Skript 3 Ebenen über dem aktuellen Ordner findet.

easymf74

Eine wirklich gute und sehr verständlich geschriebne Erklärung,
Vielen dank dafür

DonKult

@Julian – es gibt sie AUCH in /bin, für all jene Shells die es nicht implementieren (oder wenn die Funktionalität warum auch immer mal kaputt sein sollte). Die bash hat sie aber auch als builtins. Du kannst es selber probieren mit dem (bash-builtin kommando) „type“, e.g.
$ type echo
echo is a shell builtin
Wenn man sich die manpage zu echo ansieht wird dort auch darauf hingewissen, dass es sich um ein shell-builtin handeln kann: Den die haben durchaus (leider) manchmal ein unterschiedliches Verhalten…

Gast

Irgendwie scheint mir dein Post nicht ganz logisch…

„Würde das aktuelle Verzeichnis im Suchpfad vor den Systempfaden /usr/bin und Co. im $PATH stehen, dann könnte man ohne Probleme dem Benutzer maliziöse Skripte oder gar Programme unterschieben.“
Auf die Idee würden wohl wenige kommen, da wenige ihre Standardbefehle manipulieren wollen. Also würde man das aktuelle Verzeichnis eh (wie von dir beschrieben) ans Ende tun. Die Sicherheit ist damit dann auch gegeben, da man nur mit Root-Rechten an /usr/bin etc dran kommt und Befehle wie mv richtig gefunden werden.

Gleichzeitig ist es für die Sicherheit sicherlich nicht zuträglich die Verzeichnisse ~/bin und /usr/local/bin ans Anfang der Liste zu stellen – erstens gibt’s dafür keinen vernünftigen Grund (siehe oben) und zweitens ließen sich dann auch ohne Root-Rechte leicht eigene Skripte einschleusen, die eventuell Standardbefehle überschreiben…

Moritz

Sehr gute Zusammenfassung!

adun

Deine guten Ausführungen treffen häufig nicht auf „Shells“ allgemein zu, so durchsuchen einige durchaus das wd und parallel noch andere Pfade wie meinetwegen alles relativ zum Heimatverzeichnis. Das gilt natürlich insbesondere für Builtins (kill usw.) hier geht Bash gerne seine eigenen verworrenen Wege (abseits vom „UNIX-Weg“). Auch ist PATH ansonsten gerne mal ein „richtiges“ Array.

trompetenkaefer

Na dieser Artikel ist mal wirklich sehr, sehr auführlich 🙂
Ich schließe mich zerwas an, den Artikel werde ich bei Fragen zur Ausführung von Scripten auch verlinken 😉

aguafuertes

Prima Zusammenfassung, vielen Dank!

moik

hey ho.
danke für diesen interessanten artikel!
hat mir endlich klarheit verschafft!

Danke!

Pas

@ Kommentar 13 von Gast: Das leuchtet mir ein – wie bekomme ich denn mein ~/bin ans Ende der $PATH-Variable?

freebirth_one

Was ich auch mal kurz sagen wollte: unter Windows gibt es _auch_ eine PATH-Variable; kann man sich unter Systemsteuerung–>System–>Erweitert–>Umgebungsvariablen (oder so, hab gerade kein Windows zur Hand) anschauen. Gilt zumindest bis einschließlich XP.

Der einzige Unterschied zu Linux: unter Windows (bzw der Eingabeaufforderung) wird _zuerst_im aktuellen Pfad geschaut, und _danach_ die Verzeichnisse in der Variable durchsucht.

Außerdem (nur so am Rande) kann man einstellen, in welcher Reihenfolge nach übereinstimungen mit ausführbaren Dateiendungen gesucht wird.

Das haben früher sehr viele Viren ausgenutzt.

Das mit der Pfadvariable findet man spätestens dann heraus, wenn man selber anfäng zu Programmieren (ARM-Tools, Java, usw)

Marcus

Sehr gut, Danke! Jetzt rag ich mich nur noch was sbin ist?

ultima-fan

Hallo Chrisss,

schön zusammengefasst, aber eine Problematik bei mir.
Ich leere den Pfad a la $ [export] PATH=
damit ist $PATH leer. Stelle ich mich jetzt nach /bin oder in ein anderes [s]bin-Verzeichnis, kann ich einfach nur den jeweiligen befehl eingeben und es funktionert.
ich habe erwartet in /bin stehend : ./ls zu machen
aber es funktioniert auch nur ls. Warum ?

ultima-fan

Hi, hab mich vielleicht falsch ausgedrückt.
Innerhalb der Shell hab ich die Variable mit „PATH=“ geleert. Das führt dazu, dass z.B. unter / eine Eingabe von „ls“ mit „ls: command not found“ angegeben wird. Unter /bin
funktioniert ls aber trotzdem ohne PATH. Also „echo $PATH“ bringt nichts als gähnende Leere.

Ich hab aus Sicherheit sogar für den User innerhalb der /etc/profile den PATH geleert und alle login-Scripte im Heimatverzeichnis vorsorglich vom PATH Eintrag gesäubert. Problem bleibt.

Testsysteme: Ubuntu 9.04 und Debian 5.0.3 Lenny

freebirt_one

um bei einer laufenden Bash die Veränderungen neu einzulesen reicht es eigentlich, die entsprechenden Dateien zu „sourcen“. Unter Bash klappt das mittels „. „

falkbizz

Hallo Christoph.

Ich bin echt begeistert!
Endlich mal verständlich erklärt. Eigentlich ganz einfach 🙂
Danke

Wolfgang Franz

Wie bekomme ich ein „Testscript.bash“ in /home/meinName/bin/?

Wolfgang Franz

wie bekommen ich eine „Testscript.bash“-Datei in /home/user/bin/?

easymf74

Weis jetzt nicht wie du das genau meinst:
entweder erstellen: cd /home/user/bin/; nano Testscript.bash
oder verschieben: mv Testscript.bash /home/user/bin/
oder kopieren: cp Testscript.bash /home/user/bin/
oder verlinken: cd /home/user/bin/; ln -s /Pfad/zum/Testscript.bash Testscript.bash
Wenn der Pfad außerhalb deines Homeverzeichnisses liegt, dann musst du noch sudo vor die Befehle setzten um die Schreibrechte zu bekommen.