Perché hai bisogno di ./ (punto-barra) prima dell'eseguibile o del nome dello script per eseguirlo in bash?


288

Quando eseguo script in bash, devo scrivere ./all'inizio:

$ ./manage.py syncdb

In caso contrario, viene visualizzato un messaggio di errore:

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

Qual è la ragione di ciò? Ho pensato che fosse .un alias per la cartella corrente, e quindi queste due chiamate dovrebbero essere equivalenti.

Inoltre non capisco perché non ho bisogno ./quando eseguo applicazioni, come:

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

(che funziona senza ./)


4
Questo è il miglior documento sulla questione che ho incontrato finora: linfo.org/dot_slash.html
odigity

Risposte:


307

Perché su Unix, di solito, la directory corrente non è in $PATH.

Quando si digita un comando, la shell cerca un elenco di directory, come specificato dalla PATHvariabile. La directory corrente non è in quell'elenco.

Il motivo per non avere la directory corrente in quell'elenco è la sicurezza.

Diciamo che sei root e vai nella directory di un altro utente e digita slinvece di ls. Se la directory corrente è in PATH, la shell tenterà di eseguire il slprogramma in quella directory (poiché non esiste un altro slprogramma). Quel slprogramma potrebbe essere dannoso.

Funziona con ./quanto POSIX specifica che un nome di comando che contiene /verrà utilizzato come un nome di file direttamente, sopprimendo una ricerca in $PATH. Avresti potuto usare il percorso completo per lo stesso identico effetto, ma ./è più breve e più facile da scrivere.

MODIFICARE

Quella slparte era solo un esempio. Le directory in PATHvengono cercate in sequenza e quando viene effettuata una corrispondenza, quel programma viene eseguito. Quindi, a seconda di come PATHappare, digitare un comando normale può o non può essere sufficiente per eseguire il programma nella directory corrente.


47
Non è necessario digitare male nulla. L'utente potrebbe aver appena scaricato un pacchetto dannoso che contiene un lseseguibile al suo interno.
Juliano,

13
Solo una nota a tutti che dicono che questo è solo in Unix e non in Windows, questo è lo stesso in Powershell - devi eseguire .\my.batecc per eseguire
manojlds

1
@gaearon ergh, ho detto "non è un alias", quando avrebbe dovuto essere "è strettamente un alias".
Charles Duffy,

4
Questa è stata una spiegazione molto utile. Più di 20 anni fa, quando ho lavorato un po 'con DOS, penso che CMD avrebbe controllato la directory corrente, e poi il PERCORSO, quindi il comportamento di Linux non era quello che mi aspettavo, ma ha molto senso.
TecBrat il

2
@cnicutar: È interessante notare che oggi ho scoperto che esiste un slcomando chiamato locomotiva a vapore anche se non disponibile per impostazione predefinita ;-)
blackSmith

51

Quando bash interpreta la riga di comando, cerca i comandi nelle posizioni descritte nella variabile d'ambiente $PATH. Per vederlo digita:

echo $PATH

Avrai alcuni percorsi separati da due punti. Come vedrai, il percorso corrente di .solito non è incluso $PATH. Quindi Bash non riesce a trovare il tuo comando se si trova nella directory corrente. Puoi cambiarlo avendo:

PATH=$PATH:.

Questa riga aggiunge la directory corrente in $PATHmodo da poter fare:

manage.py syncdb

E ' non è raccomandato in quanto ha problema di sicurezza, più si può avere comportamenti strani, come .varia su directory ci si trova in :)

Evitare:

PATH=.:$PATH

Come puoi "mascherare" alcuni comandi standard e aprire la porta alla violazione della sicurezza :)

Solo i miei due centesimi.


42

Lo script, quando nella directory home non verrà trovato quando la shell esamina la $PATHvariabile di ambiente per trovare lo script.

La ./dice 'guardare nella directory corrente per il mio script, piuttosto che guardando tutte le directory specificate nel $PATH'.


5

Quando includi il '.' stai essenzialmente dando il "percorso completo" allo script bash eseguibile, quindi la tua shell non ha bisogno di controllare la tua variabile PATH. Senza il '.' la tua shell cercherà nella tua variabile PATH (che puoi vedere eseguendo echo $PATHper vedere se il comando che hai digitato vive in una qualsiasi delle cartelle sul tuo PATH. In caso contrario (come nel caso di manage.py) lo dice impossibile trovare il file. È considerata una cattiva pratica includere la directory corrente sul PATH, che è spiegata abbastanza bene qui: http://www.faqs.org/faqs/unix-faq/faq/part2/section- 13.html


2

Su * nix, a differenza di Windows, la directory corrente di solito non si trova nella tua $PATHvariabile. Pertanto la directory corrente non viene cercata durante l'esecuzione dei comandi. Non hai bisogno ./di eseguire applicazioni perché queste applicazioni sono nel tuo $ PATH; molto probabilmente sono in /bino /usr/bin.


1

Questa domanda ha già delle risposte fantastiche, ma volevo aggiungerla, se il tuo eseguibile si trova sul PERCORSO e ottieni output molto diversi quando esegui

./executable

a quelli che ottieni se corri

executable

(diciamo che ti imbatti in messaggi di errore con l'uno e non l'altro), quindi il problema potrebbe essere che hai due diverse versioni dell'eseguibile sul tuo computer: una sul percorso e l'altra no.

Controlla eseguendolo

quale eseguibile

e

whereis executable

Risolveva i miei problemi ... Avevo tre versioni dell'eseguibile, solo una delle quali era stata compilata correttamente per l'ambiente.


0

Razionale per la /regola POSIX PERCORSO

La regola è stata citata in: Perché hai bisogno di ./ (punto-barra) prima dell'eseguibile o del nome dello script per eseguirlo in bash? ma vorrei spiegare perché penso che sia un buon design in modo più dettagliato.

Innanzitutto, una versione esplicita della regola è:

  • se il percorso contiene /(ad esempio ./someprog, /bin/someprog, ./bin/someprog): CWD è usato e PATH non è
  • se il percorso non contiene /(ad es. someprog): viene utilizzato PATH e CWD no

Supponiamo ora che in esecuzione:

someprog

cercherebbe:

  • relativamente alla CWD prima
  • rispetto al PERCORSO dopo

Quindi, se volevi scappare /bin/someprogdalla tua distribuzione, e hai fatto:

someprog

a volte funzionerebbe, ma altri fallirebbe, perché potresti trovarti in una directory che contiene un altro someprogprogramma non correlato .

Pertanto, impareresti presto che questo non è affidabile e finiresti per usare sempre percorsi assoluti quando vuoi usare PATH, sconfiggendo quindi lo scopo di PATH.

Questo è anche il motivo per cui avere percorsi relativi nel tuo PERCORSO è una pessima idea. Sto guardando a voi,node_modules/bin .

Al contrario, supponiamo che in esecuzione:

./someprog

Cerca:

  • prima rispetto al PERCORSO
  • rispetto a CWD dopo

Quindi, se hai appena scaricato uno script someprogda un repository git e volessi eseguirlo da CWD, non saresti mai sicuro che questo sia il vero programma che verrebbe eseguito, perché forse la tua distribuzione ha un:

/bin/someprog

che è in te PERCORSO da un pacchetto che hai installato dopo aver bevuto troppo dopo Natale l'anno scorso.

Pertanto, ancora una volta, saresti costretto a eseguire sempre script locali relativi a CWD con percorsi completi per sapere cosa stai eseguendo:

"$(pwd)/someprog"

che sarebbe anche estremamente fastidioso.

Un'altra regola che potresti essere tentato di inventare sarebbe:

i percorsi relativi usano solo PATH, i percorsi assoluti solo CWD

ma ancora una volta questo costringe gli utenti a usare sempre percorsi assoluti per script non PATH con "$(pwd)/someprog".

La /regola di ricerca del percorso offre una soluzione semplice da ricordare al problema about:

  • barra: non usare PATH
  • nessuna barra: utilizzare solo PATH

il che rende super facile sapere sempre cosa stai eseguendo, basandosi sul fatto che i file nella directory corrente possono essere espressi come ./somefileo somefile, e quindi dà un significato speciale a uno di essi.

A volte, è leggermente fastidioso non poter cercare in some/progrelazione a PATH, ma non vedo una soluzione più sana a questo.


-1

Quando lo script non è nel percorso, è necessario farlo. Per maggiori informazioni leggi http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_01.html


5
... Cordiali saluti, in #bash su irc.freenode.org, correggiamo costantemente i malintesi che le persone hanno appreso da TLDP (in particolare la Guida avanzata di Bash). Come tale, dirigere le persone c'è ... forse non è l'ideale. (La nostra documentazione introduttiva preferita è mywiki.wooledge.org/BashGuide )
Charles Duffy,

-2

Tutto ha un'ottima risposta alla domanda, e sì, questo è applicabile solo quando lo si esegue nella directory corrente, a meno che non si includa il percorso assoluto. Vedi i miei campioni di seguito.

Inoltre, il (punto-barra) ha senso per me quando ho il comando sulla cartella figlio tmp2 (/ tmp / tmp2) e usa (doppia barra-punto).

CAMPIONE:

[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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.