¿Por qué necesita ./ (punto-barra) antes del ejecutable o el nombre del script para ejecutarlo en bash?

288

Al ejecutar scripts en bash, tengo que escribir ./al principio:

$ ./manage.py syncdb

Si no lo hago, recibo un mensaje de error:

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

¿Cuál es la razón para esto? Pensé que .era un alias para la carpeta actual y, por lo tanto, estas dos llamadas deberían ser equivalentes.

Tampoco entiendo por qué no lo necesito ./cuando ejecuto aplicaciones, como:

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

(que corre sin ./)

Dan Abramov
fuente
44
Este es el mejor documento sobre el asunto que he encontrado hasta ahora: linfo.org/dot_slash.html
odigity

Respuestas:

307

Porque en Unix, por lo general, el directorio actual no está en $PATH.

Cuando escribe un comando, el shell busca una lista de directorios, según lo especificado por la PATHvariable. El directorio actual no está en esa lista.

La razón para no tener el directorio actual en esa lista es la seguridad.

Digamos que eres root e ingresas al directorio de otro usuario y escribes en sllugar de ls. Si el directorio actual está dentro PATH, el shell intentará ejecutar el slprograma en ese directorio (ya que no hay otro slprograma). Ese slprograma puede ser malicioso.

Funciona con ./porque POSIX especifica que un nombre de comando que contiene un /se utilizará directamente como nombre de archivo, suprimiendo una búsqueda en $PATH. Podría haber utilizado la ruta completa para el mismo efecto exacto, pero ./es más corto y más fácil de escribir.

EDITAR

Esa slparte fue solo un ejemplo. Los directorios PATHse buscan secuencialmente y cuando se hace una coincidencia, se ejecuta ese programa. Entonces, dependiendo de cómo se PATHvea, escribir un comando normal puede o no ser suficiente para ejecutar el programa en el directorio actual.

cnicutar
fuente
47
No necesitas escribir mal nada. Es posible que el usuario haya descargado un paquete malicioso que contiene un lsarchivo ejecutable.
Juliano
13
Solo una nota para todos diciendo que esto es solo en Unix y no en Windows, esto es lo mismo en Powershell - tienes que hacer .\my.batetc. para ejecutarlo
manojlds
1
@gaearon ergh, dije "no es un alias", cuando eso debería haber sido "es estrictamente un alias".
Charles Duffy
44
Esa fue una explicación muy útil. Hace más de 20 años, cuando trabajé un poco con DOS, creo que CMD verificaría el directorio actual, y ENTONCES la RUTA, por lo que el comportamiento de Linux no era lo que esperaba, pero tiene MUCHO sentido.
TecBrat
2
@cnicutar: Curiosamente, hoy encontré que hay un slcomando llamado locomotora de vapor, aunque no está disponible por defecto ;-)
blackSmith
51

Cuando bash interpreta la línea de comando, busca comandos en las ubicaciones descritas en la variable de entorno $PATH. Para verlo escriba:

echo $PATH

Tendrás algunos caminos separados por dos puntos. Como verá, la ruta actual .generalmente no está en $PATH. Entonces Bash no puede encontrar su comando si está en el directorio actual. Puede cambiarlo teniendo:

PATH=$PATH:.

Esta línea agrega el directorio actual $PATHpara que pueda hacer:

manage.py syncdb

Es no se recomienda ya que tiene problema de seguridad, además de que puede tener comportamientos extraños, como .varía dependiendo del directorio que está en :)

Evitar:

PATH=.:$PATH

Como puede "enmascarar" algún comando estándar y abrir la puerta a la violación de seguridad :)

Solo mis dos centavos.

neuro
fuente
42

Su script, cuando esté en su directorio de inicio, no se encontrará cuando el shell mire el $PATH variable de entorno para encontrar su secuencia de comandos.

El ./dice 'busca en mi directorio actual mi script en lugar de mirar todos los directorios especificados en $PATH'.

mdm
fuente
5

Cuando incluye el '.' esencialmente está dando la "ruta completa" al script bash ejecutable, por lo que su shell no necesita verificar su variable PATH. Sin el '.' su shell se verá en su variable PATH (que puede ver ejecutando echo $PATHpara ver si el comando que escribió se encuentra en alguna de las carpetas de su PATH. Si no lo hace (como es el caso con manage.py) lo dice no puedo encontrar el archivo. Se considera una mala práctica incluir el directorio actual en su RUTA, que se explica razonablemente bien aquí: http://www.faqs.org/faqs/unix-faq/faq/part2/section- 13.html

Mark Drago
fuente
2

En * nix, a diferencia de Windows, el directorio actual generalmente no está en su $PATHvariable. Por lo tanto, el directorio actual no se busca al ejecutar comandos. No necesita ./ejecutar aplicaciones porque estas aplicaciones están en su $ PATH; lo más probable es que estén en /bino /usr/bin.

Anomia
fuente
1

Esta pregunta ya tiene algunas respuestas increíbles, pero quería agregar eso, si su ejecutable está en la RUTA, y obtiene resultados muy diferentes cuando ejecuta

./executable

a los que obtienes si corres

executable

(supongamos que se encuentra con mensajes de error con uno y no con el otro), entonces el problema podría ser que tiene dos versiones diferentes del ejecutable en su máquina: una en la ruta y la otra no.

Comprueba esto ejecutando

cual ejecutable

y

whereis executable

Solucionó mis problemas ... Tenía tres versiones del ejecutable, solo una de las cuales se compiló correctamente para el entorno.

KR_Henninger
fuente
0

Justificación de la / regla POSIX PATH

La regla se mencionó en: ¿Por qué necesita ./ (punto-barra) antes del ejecutable o el nombre del script para ejecutarlo en bash?pero me gustaría explicar por qué creo que es un buen diseño con más detalle.

Primero, una versión completa explícita de la regla es:

  • Si la ruta contiene /(por ejemplo ./someprog, /bin/someprog,./bin/someprog ): se usa CWD y PATH no
  • si la ruta no contiene /(p someprog. ej. ): se utiliza PATH y CWD no

Ahora, supongamos que se ejecuta:

someprog

buscaría:

  • en relación con CWD primero
  • relativo a la RUTA después

Entonces, si querías huir /bin/someprogde tu distribución, y lo hiciste:

someprog

a veces funcionaría, pero otras fallaría, porque podría estar en un directorio que contiene otro no relacionado someprog programa .

Por lo tanto, pronto aprenderá que esto no es confiable, y terminaría siempre usando rutas absolutas cuando quiera usar PATH, por lo tanto, anulará el propósito de PATH.

Esta es también la razón por la que tener rutas relativas en su RUTA es una muy mala idea. Te estoy mirandonode_modules/bin .

Por el contrario, supongamos que se ejecuta:

./someprog

Buscaría:

  • relativo a la RUTA primero
  • relativo a CWD después

Luego, si acaba de descargar un script someprogde un repositorio de git y desea ejecutarlo desde CWD, nunca estaría seguro de que este es el programa real que se ejecutaría, porque tal vez su distribución tiene un:

/bin/someprog

que está en su RUTA de algún paquete que instaló después de beber demasiado después de Navidad el año pasado.

Por lo tanto, una vez más, se vería obligado a ejecutar siempre scripts locales en relación con CWD con rutas completas para saber lo que está ejecutando:

"$(pwd)/someprog"

lo cual sería extremadamente molesto también.

Otra regla que podría verse tentado a inventar sería:

las rutas relativas solo usan RUTA, las rutas absolutas solo CWD

pero una vez más, esto obliga a los usuarios a usar siempre rutas absolutas para scripts que no son de RUTA con "$(pwd)/someprog" .

La /regla de búsqueda de ruta ofrece una solución fácil de recordar para el problema:

  • barra oblicua: no use PATH
  • sin barra: solo use PATH

lo que hace que sea muy fácil saber siempre lo que está ejecutando, confiando en el hecho de que los archivos en el directorio actual se pueden expresar como ./somefileo somefile, por lo que le da un significado especial a uno de ellos.

A veces, es un poco molesto que no se puede buscar en some/progrelación PATH, pero no veo una solución más sensata para esto.

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

Cuando el script no está en la ruta, se requiere que lo haga. Para obtener más información, lea http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_01.html

Gayan Hewa
fuente
55
... Para su información, en #bash en irc.freenode.org, estamos corrigiendo constantemente los malentendidos que la gente ha aprendido de TLDP (particularmente la Guía avanzada de Bash). Como tal, dirigir a las personas allí ... tal vez no sea lo ideal. (Nuestra documentación introductoria preferida es mywiki.wooledge.org/BashGuide )
Charles Duffy
-2

Todo tiene una gran respuesta a la pregunta, y sí, esto solo es aplicable cuando se ejecuta en el directorio actual, a menos que incluya la ruta absoluta. Ver mis muestras a continuación.

Además, el (punto-barra) tenía sentido para mí cuando tengo el comando en la carpeta secundaria tmp2 (/ tmp / tmp2) y usa (doble barra-punto).

MUESTRA:

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