¿Por qué no usar shebangs sin camino?

Respuestas:

20

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 execveal nuevo proceso.

El kernel no realiza ninguna interpretación en la ruta en execve(depende de las funciones de envoltura, como execvprealizar una búsqueda de RUTA) o en un shebang (que más o menos redirige la execvellamada 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 :

  • La persona que llama no tiene que preocuparse si un programa para ejecutar es un script de shell o un binario nativo.
  • El script en sí especifica qué intérprete usar, en lugar de la persona que llama.
  • El núcleo usa el nombre del script en los registros.

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/envshebang .

¹ 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.

Gilles 'SO- deja de ser malvado'
fuente
2
No, el núcleo no requiere una ruta absoluta execveni en el shebang, aunque tiene poco sentido tener una ruta relativa en un shebang.
Stéphane Chazelas
3
Para cualquiera que tenga curiosidad acerca de cómo "shebang redirige la llamada ejecutiva internamente": en realidad es parte de un mecanismo genérico para ejecutar intérpretes en ejecutables que los necesitan. Los ejecutables ELF vinculados dinámicamente son "interpretados" por /lib64/ld-linux-x86-64.so.2(ver lddsalida). Linux lo hace completamente genérico: el binfmtsoporte (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 .exeinvocación de PE32 winecuando los ejecuta, invocar la clase Java y los archivos jar java, etc., etc.
Peter Cordes
#! / usr / bin / env -S [shebang] fue necesario para ejecutar el nodo sin conocer su ruta (usando nvm, que lo coloca en una ubicación diferente de la que originalmente esperaba).
TamusJRoyce
-S solo está disponible desde coreutils 8.30. Ver gitlab.com/gnuwget/wget/commit/… .
Tim Ruehsen rockdaboot
19

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 PATHrealmente 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 perlde forma portátil o similar, es usar #!/usr/bin/env perl. Se ejecuta el núcleo /usr/bin/env, que hereda una PATHvariable de entorno. envhallazgos (en este ejemplo) perlen PATHy utiliza la execve(2)llamada al sistema para obtener el kernel para ejecutar el perlejecutable.

Bruce Ediger
fuente
4
$ 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.

Hauke ​​Laging
fuente
1
La conversión a la ruta completa se realiza mediante el shell Gracias, aunque ... ¿se supone que el ejemplo ilustra eso? A mi modo de ver, el shell se está ejecutando strace(convertido /usr/bin/straceen algún momento) con 2 argumentos.
Alois Mahdal