Warum benötigen Sie ./ (Schrägstrich) vor der ausführbaren Datei oder dem Skriptnamen, um es in Bash auszuführen?

288

Wenn ich Skripte in Bash ausführe, muss ich ./am Anfang schreiben :

$ ./manage.py syncdb

Wenn nicht, erhalte ich eine Fehlermeldung:

$ manage.py syncdb
-bash: manage.py: command not found

Was ist der Grund dafür? Ich dachte, es .ist ein Alias ​​für den aktuellen Ordner, und daher sollten diese beiden Aufrufe gleichwertig sein.

Ich verstehe auch nicht, warum ich ./beim Ausführen von Anwendungen nicht benötige , wie zum Beispiel:

user:/home/user$ cd /usr/bin
user:/usr/bin$ git

(was ohne läuft ./)

Dan Abramov
quelle
4
Dies ist das beste Dokument zu dem Thema, auf das ich bisher gestoßen
bin

Antworten:

306

Denn unter Unix befindet sich das aktuelle Verzeichnis normalerweise nicht $PATH.

Wenn Sie einen Befehl eingeben, sucht die Shell nach einer Liste von Verzeichnissen, die von der PATHVariablen angegeben werden . Das aktuelle Verzeichnis befindet sich nicht in dieser Liste.

Der Grund dafür, dass das aktuelle Verzeichnis nicht in dieser Liste enthalten ist, ist die Sicherheit.

Angenommen, Sie sind root und gehen in das Verzeichnis eines anderen Benutzers und geben slstattdessen ein ls. Wenn sich das aktuelle Verzeichnis befindet PATH, versucht die Shell, das slProgramm in diesem Verzeichnis auszuführen (da es kein anderes slProgramm gibt). Dieses slProgramm könnte bösartig sein.

Dies funktioniert, ./da POSIX angibt, dass ein Befehlsname, der a enthält, /direkt als Dateiname verwendet wird, wodurch eine Suche in unterdrückt wird $PATH. Sie hätten den vollständigen Pfad für genau den gleichen Effekt verwenden können, ./ist jedoch kürzer und einfacher zu schreiben.

BEARBEITEN

Dieser slTeil war nur ein Beispiel. Die Verzeichnisse in PATHwerden nacheinander durchsucht, und wenn eine Übereinstimmung hergestellt wird, wird dieses Programm ausgeführt. Je nachdem, wie es PATHaussieht, reicht es möglicherweise aus, einen normalen Befehl einzugeben, um das Programm im aktuellen Verzeichnis auszuführen.

cnicutar
quelle
47
Sie müssen nichts falsch eingeben. Der Benutzer hat möglicherweise gerade ein Schadpaket heruntergeladen, das eine lsausführbare Datei enthält .
Juliano
13
Nur eine Anmerkung an alle, die sagen, dass dies nur unter Unix und nicht unter Windows der .\my.bat
Fall
1
@gaearon ergh, ich sagte "ist kein Alias", wenn das hätte sein sollen "ist streng ein Alias".
Charles Duffy
4
Das war eine sehr hilfreiche Erklärung. Vor mehr als 20 Jahren, als ich ein wenig mit DOS gearbeitet habe, denke ich, dass CMD das aktuelle Verzeichnis und dann den Pfad überprüfen würde. Das Verhalten von Linux war also nicht das, was ich erwartet hatte, aber es macht sehr viel Sinn.
TecBrat
2
@cnicutar: Interessanterweise fand ich heute, dass es einen slBefehl namens Dampflokomotive gibt, obwohl standardmäßig nicht verfügbar
;-)
51

Wenn bash die Befehlszeile interpretiert, sucht es an den in der Umgebungsvariablen beschriebenen Stellen nach Befehlen $PATH. Um es zu sehen, geben Sie Folgendes ein:

echo $PATH

Sie haben einige Pfade, die durch Doppelpunkte getrennt sind. Wie Sie sehen werden, ist der aktuelle Pfad .normalerweise nicht in $PATH. Daher kann Bash Ihren Befehl nicht finden, wenn er sich im aktuellen Verzeichnis befindet. Sie können es ändern, indem Sie:

PATH=$PATH:.

Diese Zeile fügt das aktuelle Verzeichnis hinzu, $PATHdamit Sie Folgendes tun können:

manage.py syncdb

Es wird nicht empfohlen, da es Sicherheitsprobleme gibt und Sie seltsame Verhaltensweisen haben können, .die von dem Verzeichnis abhängen, in dem Sie sich befinden :)

Vermeiden:

PATH=.:$PATH

Da können Sie einen Standardbefehl „maskieren“ und die Tür für Sicherheitsverletzungen öffnen :)

Nur meine zwei Cent.

Neuro
quelle
42

Ihr Skript in Ihrem Ausgangsverzeichnis wird nicht gefunden, wenn die Shell die $PATHUmgebungsvariable überprüft, um Ihr Skript zu finden.

Das ./lautet "Suchen Sie im aktuellen Verzeichnis nach meinem Skript, anstatt alle in angegebenen Verzeichnisse zu suchen $PATH".

mdm
quelle
5

Wenn Sie das '.' Sie geben im Wesentlichen den "vollständigen Pfad" zum ausführbaren Bash-Skript an, sodass Ihre Shell Ihre PATH-Variable nicht überprüfen muss. Ohne das '.' Ihre Shell sucht in Ihrer PATH-Variablen (die Sie durch Ausführen echo $PATHsehen können, um festzustellen , ob der von Ihnen eingegebene Befehl in einem der Ordner in Ihrem PATH gespeichert ist. Wenn dies nicht der Fall ist (wie dies bei manage.py der Fall ist), wird dies angegeben Die Datei kann nicht gefunden werden. Es wird als schlechte Praxis angesehen, das aktuelle Verzeichnis in Ihren PATH aufzunehmen, was hier ziemlich gut erklärt wird: http://www.faqs.org/faqs/unix-faq/faq/part2/section- 13.html

Mark Drago
quelle
2

Unter * nix befindet sich das aktuelle Verzeichnis im Gegensatz zu Windows normalerweise nicht in Ihrer $PATHVariablen. Daher wird das aktuelle Verzeichnis bei der Ausführung von Befehlen nicht durchsucht. Sie brauchen nicht ./zum Ausführen von Anwendungen , da diese Anwendungen sind in Ihrem $ PATH; höchstwahrscheinlich sind sie in /binoder /usr/bin.

Anomie
quelle
1

Diese Frage hat bereits einige großartige Antworten, aber ich wollte das hinzufügen, wenn sich Ihre ausführbare Datei auf dem Pfad befindet und Sie beim Ausführen sehr unterschiedliche Ausgaben erhalten

./executable

zu denen, die du bekommst, wenn du rennst

executable

(Nehmen wir an, Sie stoßen mit der einen und nicht mit der anderen auf Fehlermeldungen), dann könnte das Problem darin bestehen, dass Sie zwei verschiedene Versionen der ausführbaren Datei auf Ihrem Computer haben: eine auf dem Pfad und die andere nicht.

Überprüfen Sie dies durch Ausführen

welche ausführbare Datei

und

whereis executable

Es hat meine Probleme behoben ... Ich hatte drei Versionen der ausführbaren Datei, von denen nur eine für die Umgebung korrekt kompiliert wurde.

KR_Henninger
quelle
0

Begründung für die /POSIX PATH-Regel

Die Regel wurde erwähnt unter: Warum benötigen Sie ./ (Schrägstrich) vor der ausführbaren Datei oder dem Skriptnamen, um sie in Bash auszuführen? aber ich möchte näher erläutern, warum ich denke, dass dies ein gutes Design ist.

Erstens lautet eine explizite Vollversion der Regel:

  • Wenn der Pfad enthält /( zum Beispiel ./someprog, /bin/someprog, ./bin/someprog): CWD verwendet wird und ist nicht PATH
  • Wenn der Pfad nicht enthält /(z. B. someprog): PATH wird verwendet und CWD nicht

Angenommen, es läuft:

someprog

würde suchen:

  • relativ zu CWD zuerst
  • relativ zu PATH nach

Dann, wenn Sie /bin/someprogvon Ihrer Distribution weglaufen wollten und Sie taten:

someprog

es würde manchmal funktionieren, aber andere würden fehlschlagen, weil Sie sich möglicherweise in einem Verzeichnis befinden, das ein anderes nicht verwandtes someprogProgramm enthält .

Daher würden Sie bald feststellen, dass dies nicht zuverlässig ist, und Sie würden am Ende immer absolute Pfade verwenden, wenn Sie PATH verwenden möchten, wodurch der Zweck von PATH zunichte gemacht wird.

Dies ist auch der Grund, warum es eine wirklich schlechte Idee ist, relative Pfade in Ihrem Pfad zu haben. Ich sehe dich annode_modules/bin .

Nehmen wir umgekehrt an, dass Laufen:

./someprog

Würde suchen:

  • relativ zu PATH zuerst
  • relativ zu CWD nach

Wenn Sie dann gerade ein Skript someprogaus einem Git-Repository heruntergeladen und von CWD ausführen möchten, wären Sie sich nie sicher, ob dies das eigentliche Programm ist, das ausgeführt wird, da Ihre Distribution möglicherweise Folgendes hat:

/bin/someprog

Das ist in dir PATH von einem Paket, das du installiert hast, nachdem du letztes Jahr nach Weihnachten zu viel getrunken hast.

Daher wären Sie erneut gezwungen, immer lokale Skripte relativ zu CWD mit vollständigen Pfaden auszuführen, um zu wissen, was Sie ausführen:

"$(pwd)/someprog"

das wäre auch extrem nervig.

Eine andere Regel, die Sie möglicherweise in Versuchung führen könnten, wäre:

Relative Pfade verwenden nur PATH, absolute Pfade nur CWD

Dies zwingt die Benutzer jedoch erneut dazu, für Nicht-PATH-Skripte mit immer absolute Pfade zu verwenden "$(pwd)/someprog".

Die /Pfadsuchregel bietet eine einfach zu merkende Lösung für das About-Problem:

  • Schrägstrich: nicht verwenden PATH
  • kein Schrägstrich: nur verwenden PATH

Dies macht es sehr einfach, immer zu wissen, was Sie ausführen, indem Sie sich auf die Tatsache verlassen, dass Dateien im aktuellen Verzeichnis entweder als ./somefileoder ausgedrückt werden können somefile, und gibt daher einer von ihnen eine besondere Bedeutung.

Manchmal ist es etwas ärgerlich, dass Sie nicht some/progrelativ zu suchen können PATH, aber ich sehe keine vernünftigere Lösung dafür.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
-1

Wenn sich das Skript nicht im Pfad befindet, ist dies erforderlich. Weitere Informationen finden Sie unter http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_01.html

Gayan Hewa
quelle
5
... Zu Ihrer Information, in #bash auf irc.freenode.org korrigieren wir ständig Missverständnisse, die Menschen von TLDP gelernt haben (insbesondere den Advanced Bash Guide). Als solches ist es ... vielleicht nicht ideal, Leute dorthin zu führen. (Unsere bevorzugte Einführungsdokumentation ist mywiki.wooledge.org/BashGuide )
Charles Duffy
-2

Alle haben eine gute Antwort auf die Frage, und ja, dies gilt nur, wenn sie im aktuellen Verzeichnis ausgeführt werden, es sei denn, Sie geben den absoluten Pfad an. Siehe meine Beispiele unten.

Außerdem machte der (Punkt-Schrägstrich) für mich Sinn, wenn ich den Befehl für den untergeordneten Ordner tmp2 (/ tmp / tmp2) habe und ihn verwendet (doppelter Punkt-Schrägstrich).

STICHPROBE:

[fifiip-172-31-17-12 tmp]$ ./StackO.sh

Hello Stack Overflow

[fifi@ip-172-31-17-12 tmp]$ /tmp/StackO.sh

Hello Stack Overflow

[fifi@ip-172-31-17-12 tmp]$ mkdir tmp2

[fifi@ip-172-31-17-12 tmp]$ cd tmp2/

[fifi@ip-172-31-17-12 tmp2]$ ../StackO.sh

Hello Stack Overflow
FIFI
quelle