¿Es posible tener un shebang que, en lugar de especificar una ruta a un intérprete, tenga el nombre del intérprete y permita que el shell lo encuentre a través de $ PATH?
Si no, ¿hay alguna razón por la cual?
¿Es posible tener un shebang que, en lugar de especificar una ruta a un intérprete, tenga el nombre del intérprete y permita que el shell lo encuentre a través de $ PATH?
Si no, ¿hay alguna razón por la cual?
Respuestas:
La búsqueda de RUTA es una característica de la biblioteca C estándar en el espacio de usuario, al igual que las variables de entorno en general. El núcleo no ve las variables de entorno, excepto cuando pasa sobre un entorno desde el llamador execve
al nuevo proceso.
El kernel no realiza ninguna interpretación en la ruta en execve
(depende de las funciones de envoltura, como execvp
realizar una búsqueda de RUTA) o en un shebang (que más o menos redirige la execve
llamada internamente). Por lo tanto, debe poner la ruta absoluta en el shebang¹. La implementación original de shebang fue solo unas pocas líneas de código, y no se ha expandido significativamente desde entonces.
En las primeras versiones de Unix, el shell hizo el trabajo de invocar a sí mismo cuando notó que estaba invocando un script. Shebang fue agregado al núcleo por varias razones (resumiendo la justificación de Dennis Ritchie :
Los shebangs sin ruta requerirían aumentar el kernel para acceder a las variables de entorno y el proceso PATH
, o hacer que el kernel ejecute un programa de espacio de usuario que realice la búsqueda PATH. El primer método requiere agregar una cantidad desproporcionada de complejidad al núcleo. El segundo método ya es posible con un #!/usr/bin/env
shebang .
¹ Si coloca una ruta relativa, se interpreta relativamente en el directorio actual del proceso (no en el directorio que contiene la secuencia de comandos), lo cual no es útil en un shebang.
execve
ni en el shebang, aunque tiene poco sentido tener una ruta relativa en un shebang.
/lib64/ld-linux-x86-64.so.2
(ver ldd
salida). Linux lo hace completamente genérico: el binfmt
soporte (desde 2.1.43) le permite registrar pares de ruta de intérprete / número mágico o extensión de archivo. Puede ejecutar la .exe
invocación de PE32 wine
cuando los ejecuta, invocar la clase Java y los archivos jar java
, etc., etc.
Están sucediendo más de lo que parece. #!
las líneas son interpretadas por el kernel de Unix o Linux, #!
no es un aspecto de los shells. Esto significa que PATH
realmente no existe en el momento en que el núcleo decide qué ejecutar.
La forma más común de lidiar con no saber qué ejecutable ejecutar, o llamar perl
de forma portátil o similar, es usar #!/usr/bin/env perl
. Se ejecuta el núcleo /usr/bin/env
, que hereda una PATH
variable de entorno. env
hallazgos (en este ejemplo) perl
en PATH
y utiliza la execve(2)
llamada al sistema para obtener el kernel para ejecutar el perl
ejecutable.
$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0
La conversión a la ruta completa la realiza el shell (más general: en el espacio de usuario). El kernel espera un nombre / ruta de archivo al que pueda acceder directamente.
Si desea que el sistema encuentre su ejecutable mirando a través de la variable PATH, puede reescribir su shebang como #!/usr/bin/env EXEC
.
Pero también en este caso no es el núcleo quien hace la búsqueda.
strace
(convertido /usr/bin/strace
en algún momento) con 2 argumentos.