Esta puede ser una pregunta tonta, pero aún la hago. Si he declarado un shebang
#!/bin/bash
al principio de my_shell_script.sh
, así que siempre tengo que invocar este script usando bash
[my@comp]$bash my_shell_script.sh
o puedo usar por ejemplo
[my@comp]$sh my_shell_script.sh
y mi script determina el shell en ejecución usando el shebang? ¿Sucede lo mismo con ksh
Shell? Estoy usando AIX.
scripting
executable
shebang
jrara
fuente
fuente
chmod +x my_shell_script.sh ; /path/to/my_shell_script.sh # or ./my_shell_script.sh if you happen to be in its directory
Respuestas:
El shebang
#!
es una instancia legible para humanos de un número mágico que consiste en la cadena de bytes0x23 0x21
, que es utilizada por laexec()
familia de funciones para determinar si el archivo a ejecutar es un script o un binario. Cuando el shebang está presente,exec()
ejecutará el ejecutable especificado después del shebang.Tenga en cuenta que esto significa que si invoca un script especificando el intérprete en la línea de comando, como se hace en los dos casos dados en la pregunta,
exec()
ejecutará el intérprete especificado en la línea de comando, ni siquiera mirará el script.Entonces, como otros han señalado, si desea
exec()
invocar al intérprete especificado en la línea shebang, el script debe tener el bit ejecutable establecido e invocado como./my_shell_script.sh
.El comportamiento es fácil de demostrar con el siguiente script:
Explicación:
#!/bin/ksh
defineksh
ser el intérprete.$$
contiene el PID del proceso actual./proc/pid/exe
es un enlace simbólico al ejecutable del proceso (al menos en Linux; en AIX, /proc/$$/object/a.out es un enlace al ejecutable).readlink
generará el valor del enlace simbólico.Ejemplo:
Nota : Estoy demostrando esto en Ubuntu, donde el shell predeterminado
/bin/sh
es un enlace simbólico para guiar, es decir,/bin/dash
y/bin/ksh
es un enlace simbólico/etc/alternatives/ksh
, que a su vez es un enlace simbólico/bin/pdksh
.fuente
exec()
menciona en esta respuesta es una llamada al sistema, el comandoexec
es un shell incorporado, por lo que no puede invocar unexec
programa desde Node.js o Java. Sin embargo, cualquier comando de shell invocado por, por ejemplo,Runtime.exec()
en Java finalmente es procesado por laexec()
llamada al sistema.child_process.{exec(),execFile(),spawn()
}, todo se implementaría usando Cexec()
(a travésprocess
).Si lo hace Por cierto, no es una pregunta tonta. Una referencia para mi respuesta está aquí . Comenzar un script con #!
Se llama shebang o línea "bang".
No es más que el camino absoluto hacia el intérprete de Bash.
Consiste en un signo de número y un signo de exclamación (#!), Seguido de la ruta completa al intérprete como / bin / bash.
Todos los scripts en Linux se ejecutan usando el intérprete especificado en una primera línea Casi todos los scripts de bash a menudo comienzan con #! / Bin / bash (suponiendo que Bash se haya instalado en / bin) Esto garantiza que Bash se utilizará para interpretar el script, incluso si se ejecuta bajo otro shell El shebang fue presentado por Dennis Ritchie entre la Versión 7 Unix y la 8 en los Laboratorios Bell. Luego también se agregó a la línea BSD en Berkeley.
Ignorar una línea de intérprete (shebang)
Si no especifica una línea de intérprete, el valor predeterminado suele ser / bin / sh. Pero, se recomienda que establezca #! / Bin / bash line.
fuente
#!/usr/bin/perl
#!/usr/local/bin/python
#!/usr/local/bin/ruby
otra entrada común de shebang utilizada para admitir múltiples sistemas es usar env para localizar el intérprete que desea usar, como#!/usr/bin/env perl
#!/usr/bin/env python
env
, ¿cuál debería preferirse realmente? Python y Perl a menudo usanenv
, mientras que en shellscripts, esto a menudo se omite y shebang apunta al shell en cuestión.env
encontrar un programa en $ PATH es un poco hack. No establece variables de entorno como su nombre lo indica. $ PATH podría ser un resultado diferente para diferentes usuarios. Pero ayuda a que los scripts se ejecuten sin modificaciones en los sistemas que colocan un intérprete perl razonable en algún lugar extraño.La
exec
llamada al sistema del kernel de Linux comprende shebangs (#!
) de forma nativaCuando lo haces en bash:
en Linux, esto llama a la
exec
llamada del sistema con la ruta./something
.Esta línea del núcleo se llama en el archivo pasado a
exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25Lee los primeros bytes del archivo y los compara con
#!
.Si la comparación es verdadera, el núcleo de Linux analiza el resto de la línea, que realiza otra
exec
llamada con la ruta/usr/bin/env python
y el archivo actual como primer argumento:y esto funciona para cualquier lenguaje de secuencias de comandos que se use
#
como carácter de comentario.Y sí, puedes hacer un ciclo infinito con:
Bash reconoce el error:
#!
Simplemente resulta ser legible para los humanos, pero eso no es obligatorio.Si el archivo comenzó con diferentes bytes, entonces la
exec
llamada al sistema usaría un controlador diferente. El otro controlador incorporado más importante es para archivos ejecutables ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 que comprueba los bytes7f 45 4c 46
(que también son humanos legible para.ELF
). Confirmemos eso leyendo los 4 primeros bytes de/bin/ls
, que es un ejecutable ELF:salida:
Entonces, cuando el núcleo ve esos bytes, toma el archivo ELF, lo guarda en la memoria correctamente y comienza un nuevo proceso con él. Ver también: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
Finalmente, puede agregar sus propios manejadores de shebang con el
binfmt_misc
mecanismo. Por ejemplo, puede agregar un controlador personalizado para.jar
archivos . Este mecanismo incluso admite controladores por extensión de archivo. Otra aplicación es ejecutar de forma transparente ejecutables de una arquitectura diferente con QEMU .Sin embargo, no creo que POSIX especifique shebangs: https://unix.stackexchange.com/a/346214/32558 , aunque sí lo menciona en las secciones de justificación y en la forma "si el sistema admite scripts ejecutables Puede pasar".
fuente
./something
desde un shell no pasará la ruta completaexec
, sino exactamente la ruta ingresada. ¿Puedes corregir esto en tu respuesta? Hagaecho "$0"
en su script y verá que este es el caso.De hecho, si lo toma en consecuencia, el ejecutable anotado en la línea shebang, es solo un ejecutable. Tiene sentido usar algún intérprete de texto como ejecutable, pero no es necesario. Solo para aclaración y demostración, hice una prueba bastante inútil:
Nombrado el archivo test.txt y establecer el bit exectuable
chmod u+x test.txt
, a continuación, "llamada" que:./test.txt
. Como se esperaba, el contenido del archivo se emite. En este caso, el gato no ignora la línea shebang. Simplemente genera todas las líneas. Cualquier intérprete útil debería ser capaz de ignorar esta línea shebang. Para bash, perl y PHP, es simplemente una línea de comentarios. Entonces sí, estos ignoran la línea shebang.fuente
Por lo que obtuve, cada vez que un archivo tiene un conjunto de bits ejecutable y se invoca, el núcleo analiza el encabezado del archivo para determinar cómo proceder (hasta donde yo sé, puede agregar controladores personalizados para formatos de archivo personalizados a través de LKM). Si el archivo parece ser un archivo de texto con un #! combinación al principio, su ejecución se envía a otro ejecutable (generalmente una especie de shell), una ruta a la que se debe especificar directamente después de dicho shebang, en la misma línea. El núcleo luego procede a ejecutar el shell y pasa el archivo para que lo maneje.
En resumen, no importa con qué shell invoque el script: el núcleo enviará la ejecución al apropiado de cualquier manera.
fuente
bash ./myscript.sh
y./myscript.sh
.