Por que você precisa de ./ (barra) antes do nome do executável ou do script para executá-lo no bash?

288

Ao executar scripts no bash, tenho que escrever ./no começo:

$ ./manage.py syncdb

Caso contrário, recebo uma mensagem de erro:

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

Qual é a razão para isto? Eu pensei que .é um alias para a pasta atual e, portanto, essas duas chamadas devem ser equivalentes.

Também não entendo por que não preciso ./ao executar aplicativos, como:

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

(que é executado sem ./)

Dan Abramov
fonte
4
Este é o melhor documento sobre o assunto que me deparei até agora: linfo.org/dot_slash.html
odigity

Respostas:

307

Porque em Unix, normalmente, o diretório atual não está na $PATH.

Quando você digita um comando, o shell pesquisa uma lista de diretórios, conforme especificado pela PATHvariável. O diretório atual não está nessa lista.

O motivo para não ter o diretório atual nessa lista é segurança.

Digamos que você seja root e entre no diretório de outro usuário e digite em slvez de ls. Se o diretório atual estiver PATH, o shell tentará executar o slprograma nesse diretório (já que não há outro slprograma). Esse slprograma pode ser malicioso.

Ele funciona ./porque o POSIX especifica que um nome de comando que contém a /será usado diretamente como um nome de arquivo, suprimindo uma pesquisa $PATH. Você poderia ter usado o caminho completo para exatamente o mesmo efeito, mas ./é mais curto e fácil de escrever.

EDITAR

Essa slparte foi apenas um exemplo. Os diretórios PATHsão pesquisados ​​sequencialmente e, quando uma correspondência é feita, o programa é executado. Portanto, dependendo da PATHaparência, digitar um comando normal pode ou não ser suficiente para executar o programa no diretório atual.

cnicutar
fonte
47
Você não precisa digitar nada errado. O usuário pode apenas ter baixado um pacote malicioso que contém um lsexecutável.
Juliano
13
Apenas uma nota a todos dizendo que isso é apenas em Unix e não do Windows, este é o mesmo em Powershell - você tem que fazer .\my.batetc para executar
manojlds
1
@gaearon ergh, eu disse "não é um pseudônimo", quando deveria ter sido "é estritamente um pseudônimo".
Charles Duffy
4
Essa foi uma explicação muito útil. Há mais de 20 anos, quando trabalhei um pouco com o DOS, acho que o CMD verificaria o diretório atual, e então o CAMINHO, de modo que o comportamento do Linux não era o que eu esperava, mas faz muito sentido.
TecBrat
2
@cnicutar: Curiosamente, hoje eu descobri que existe um slcomando chamado locomotiva a vapor, embora não disponível por padrão ;-)
Ferreiro
51

Quando o bash interpreta a linha de comando, ele procura comandos nos locais descritos na variável de ambiente $PATH. Para vê-lo, digite:

echo $PATH

Você terá alguns caminhos separados por dois pontos. Como você verá, o caminho atual .geralmente não está $PATH. Portanto, o Bash não pode encontrar seu comando se ele estiver no diretório atual. Você pode alterá-lo tendo:

PATH=$PATH:.

Esta linha adiciona o diretório atual $PATHpara que você possa fazer:

manage.py syncdb

É não recomendado, pois tem problema de segurança, além de você pode ter comportamentos estranhos, como .varia de acordo com o diretório que você está em :)

Evitar:

PATH=.:$PATH

Como você pode "mascarar" algum comando padrão e abrir a porta para brechas de segurança :)

Apenas meus dois centavos.

neuro
fonte
42

Seu script, quando estiver no diretório inicial, não será encontrado quando o shell examinar a $PATHvariável de ambiente para encontrar seu script.

O ./texto diz 'procure no diretório atual o meu script em vez de examinar todos os diretórios especificados em $PATH'.

mdm
fonte
5

Quando você inclui o '.' você está essencialmente dando o "caminho completo" para o script executável do bash, para que seu shell não precise verificar sua variável PATH. Sem o '.' seu shell procurará na sua variável PATH (que você pode ver executando echo $PATHpara ver se o comando digitado está em alguma das pastas do seu PATH. Caso contrário, como no caso do manage.py), ele diz Não é possível encontrar o arquivo.É uma prática recomendada incluir o diretório atual no PATH, o que é razoavelmente explicado aqui: http://www.faqs.org/faqs/unix-faq/faq/part2/section- 13.html

Mark Drago
fonte
2

No * nix, diferentemente do Windows, o diretório atual geralmente não está na sua $PATHvariável. Portanto, o diretório atual não é pesquisado ao executar comandos. Você não precisa ./executar aplicativos porque esses aplicativos estão no seu $ PATH; provavelmente eles estão dentro /binou /usr/bin.

Anomie
fonte
1

Esta pergunta já tem respostas impressionantes, mas eu gostaria de acrescentar que, se o seu executável estiver no PATH, e você obtiver resultados muito diferentes ao executar

./executable

para os que você recebe se você correr

executable

(digamos que você tenha mensagens de erro com uma e não com a outra), o problema pode ser o fato de você ter duas versões diferentes do executável em sua máquina: uma no caminho e a outra não.

Verifique isso executando

qual executável

e

whereis executable

Corrigiu meus problemas ... Eu tinha três versões do executável, apenas uma delas foi compilada corretamente para o ambiente.

KR_Henninger
fonte
0

Justificativa para a /regra POSIX PATH

A regra foi mencionada em: Por que você precisa de ./ (barra) antes do nome do executável ou do script para executá-lo no bash?mas gostaria de explicar por que acho que esse é um bom design com mais detalhes.

Primeiro, uma versão completa explícita da regra é:

  • Se o caminho contém /(por exemplo ./someprog, /bin/someprog,./bin/someprog ): CWD é utilizado e não é PATH
  • se o caminho não contiver /(por exemplo someprog): PATH é usado e CWD não é

Agora, suponha que executando:

someprog

pesquisaria:

  • em relação à CWD primeiro
  • em relação ao PATH após

Então, se você queria fugir /bin/someprogda sua distribuição, e fez:

someprog

algumas vezes funcionava, mas outras falhava, porque você pode estar em um diretório que contém outro não relacionado someprog programa .

Portanto, você aprenderia em breve que isso não é confiável e acabaria sempre usando caminhos absolutos quando desejar usar o PATH, derrotando, portanto, o objetivo do PATH.

É também por isso que ter caminhos relativos no PATH é uma péssima ideia. Eu estou olhando para vocênode_modules/bin .

Por outro lado, suponha que executando:

./someprog

Pesquisaria:

  • em relação ao PATH primeiro
  • em relação à DRC após

Então, se você acabou de baixar um script someprogde um repositório git e quiser executá-lo no CWD, nunca terá certeza de que este é o programa real a ser executado, porque talvez sua distribuição possua:

/bin/someprog

que está no seu PATH de algum pacote que você instalou depois de beber demais depois do Natal do ano passado.

Portanto, mais uma vez, você seria forçado a sempre executar scripts locais relativos ao CWD com caminhos completos para saber o que está executando:

"$(pwd)/someprog"

o que seria extremamente irritante também.

Outra regra que você pode ser tentado a criar seria:

caminhos relativos usam apenas PATH, caminhos absolutos apenas CWD

mas, mais uma vez, isso força os usuários a sempre usar caminhos absolutos para scripts não PATH "$(pwd)/someprog".

A /regra de pesquisa de caminho oferece uma solução simples de lembrar para o problema sobre:

  • barra: não use PATH
  • sem barra: use apenas PATH

o que torna super fácil saber sempre o que você está executando, confiando no fato de que os arquivos no diretório atual podem ser expressos como ./somefileou somefilee, portanto, atribui um significado especial a um deles.

Às vezes, é um pouco chato que você não possa procurar em some/progrelação a PATH, mas não vejo uma solução mais saudável para isso.

Ciro Santilli adicionou uma nova foto
fonte
-1

Quando o script não está no caminho, é necessário fazê-lo. Para mais informações, leia http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_01.html

Gayan Hewa
fonte
5
... Para sua informação, no #bash em irc.freenode.org, estamos constantemente corrigindo mal-entendidos que as pessoas aprenderam com o TLDP (particularmente o Advanced Bash Guide). Como tal, direcionar as pessoas para lá ... talvez não seja o ideal. (Nossa documentação introdutória preferida é mywiki.wooledge.org/BashGuide )
Charles Duffy
-2

Tudo tem uma ótima resposta à pergunta, e sim, isso só é aplicável ao executá-lo no diretório atual, a menos que você inclua o caminho absoluto. Veja minhas amostras abaixo.

Além disso, a (barra) fez sentido para mim quando tenho o comando na pasta filho tmp2 (/ tmp / tmp2) e ela usa (barra dupla).

AMOSTRA:

[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
fonte