Articulo de referencia

Shebang (Unix)

#! "},"name":{"wt":"shebang"}},"i":0}}]}"> En informática , un shebang es la secuencia de caracteres #!, que consta de los caracteres signo de número (también conocido como almo...

En informática , un shebang es la secuencia de caracteres #!, que consta de los caracteres signo de número (también conocido como almohadilla o hash) y signo de exclamación (también conocido como bang), al principio de un script . También se le llama exclamación-argumento , sha-bang , [ 1 ] [ 2 ] hashbang , [ 3 ] [ 4 ] pound-bang , [ 5 ] [ 6 ] o hash-pling . [ 7 ]

Cuando un archivo de texto con un shebang se usa como si fuera un ejecutable en un sistema operativo tipo Unix , el mecanismo de carga de programas analiza el resto de la línea inicial del archivo como una directiva de intérprete. El cargador ejecuta el programa intérprete especificado , pasándole como argumento la ruta que se usó inicialmente al intentar ejecutar el script, para que el programa pueda usar el archivo como datos de entrada. [ 8 ] Por ejemplo, si un script se llama con la ruta ruta/al/script y comienza con la línea #!/bin/sh, entonces se le indica al cargador de programas que ejecute el programa /bin/sh , pasando ruta/al/script como primer argumento.

La línea shebang suele ser ignorada por el intérprete, ya que el carácter "#" es un marcador de comentario en muchos lenguajes de scripting; algunos intérpretes de lenguajes que no utilizan el signo de almohadilla para comenzar los comentarios aún pueden ignorar la línea shebang en reconocimiento de su propósito. [ 9 ]

Sintaxis

La forma de una directiva de intérprete shebang es la siguiente: [ 8 ]

#! intérprete [ opcional-un-único-argumento ]

donde `interpreter` es la ruta a un programa ejecutable. Es opcional dejar un espacio entre `#!` e `interpreter` . Puede haber cualquier número de espacios o tabulaciones antes o después de `interpreter` . El argumento opcional incluirá cualquier espacio adicional hasta el final de la línea.

En Linux , el archivo especificado por el intérprete se puede ejecutar si tiene los permisos de ejecución y es uno de los siguientes:

  • un ejecutable nativo, como un binario ELF
  • cualquier tipo de archivo para el que se haya registrado un intérprete a través del mecanismo binfmt_misc (como para ejecutar binarios .exe de Microsoft usando wine ).
  • otro guion que empieza con un shebang

En Linux y Minix , un intérprete también puede ser un script. Una cadena de shebangs y wrappers produce un archivo directamente ejecutable que recibe los scripts encontrados como parámetros en orden inverso. Por ejemplo, si el archivo /bin/A es un archivo ejecutable en formato ELF , el archivo /bin/B contiene el shebang #!/bin/A optparamy el archivo /bin/C contiene el shebang #!/bin/B, entonces al ejecutar el archivo /bin/C se resuelve en /bin/B /bin/C, que finalmente se resuelve en /bin/A optparam /bin/B /bin/C.

En los sistemas operativos derivados de Solaris y Darwin (como macOS ), el archivo especificado por el intérprete debe ser un binario ejecutable y no puede ser un script. [ 10 ]

Si el script se invoca llamando explícitamente al intérprete, la #!línea nunca se consulta. Por ejemplo, si script.shla primera línea de es #!/usr/games/nibbles, al ejecutar nosh script.sh intentará abrir el script en , sino que lo hará.nibbles./script.sh

Ejemplos

Algunas líneas típicas de shebang:

  • #!/bin/sh– Ejecutar el archivo usando el intérprete de comandos Bourne o un intérprete de comandos compatible, que se supone que está en el directorio /bin.
  • #!/bin/bash– Ejecuta el archivo usando el intérprete de comandos Bash.
  • #!/usr/bin/pwsh– Ejecutar el archivo usando PowerShell
  • #!/usr/bin/env python3– Ejecutar con un intérprete de Python , utilizando la ruta de búsqueda del programa env para encontrarlo.
  • #!/bin/false– No hace nada, pero devuelve un código de salida distinto de cero , lo que indica un fallo. Se utiliza para evitar la ejecución independiente de un archivo de script destinado a ejecutarse en un contexto específico, como por ejemplo mediante el .comando desde sh/bash, sourcedesde csh/tcsh, o como un archivo .profile, .cshrc o .login.

Las líneas shebang pueden incluir opciones específicas que se pasan al intérprete. Sin embargo, las implementaciones varían en el comportamiento de análisis de las opciones; para garantizar la portabilidad, solo se debe especificar una opción sin espacios en blanco intercalados. [ 11 ] A continuación se incluyen más directrices de portabilidad.

Objetivo

Las directivas de intérprete permiten utilizar scripts y archivos de datos como comandos, ocultando los detalles de su implementación a los usuarios y otros programas, al eliminar la necesidad de anteponer el intérprete a los scripts en la línea de comandos.

Por ejemplo, consideremos un script que tiene la línea inicial #!/bin/sh -x. Se puede invocar simplemente proporcionando su ruta de archivo, como some/path/to/foo, [ 12 ] y algunos parámetros, como bary baz:

algún/camino/hacia/foo bar baz

En este caso /bin/shse invoca en su lugar, con los parámetros -x, some/path/to/foo, bar, y baz, como si el comando original hubiera sido

/bin/sh -x alguna/ruta/a/foo bar baz

La mayoría de los intérpretes ponen a disposición del script cualquier argumento adicional. Si /bin/shes un intérprete de comandos compatible con POSIX , entonces bary bazse presentan al script como el array de parámetros posicionales "$@", y de forma individual como parámetros "$1"y "$2"respectivamente.

Debido a que el símbolo # inicial es el carácter que se usa para introducir comentarios en el lenguaje de shell POSIX (y en los lenguajes que entienden muchos otros intérpretes), el intérprete ignora toda la línea shebang. Sin embargo, depende del intérprete ignorar o no la línea shebang, y no todos lo hacen; por lo tanto, un script que consta de las dos líneas siguientes simplemente muestra ambas líneas al ejecutarse:

#!/cubo/gato ¡Hola Mundo!

Fortalezas

En comparación con el uso de listas de asociación globales entre extensiones de archivo y aplicaciones de interpretación, el método de directiva de intérprete permite a los usuarios utilizar intérpretes desconocidos a nivel global del sistema y sin necesidad de permisos de administrador. Además, permite la selección específica del intérprete, sin sobrecargar el espacio de nombres de las extensiones de archivo (donde una extensión hace referencia a más de un tipo de archivo), y permite cambiar el lenguaje de implementación de un script sin modificar su sintaxis de invocación por otros programas. Quienes invocan el script no necesitan conocer el lenguaje de implementación, ya que el propio script se encarga de especificar el intérprete a utilizar.

Portabilidad

Ubicación del programa

Las directivas shebang deben especificar rutas absolutas (o relativas al directorio de trabajo actual ) a los ejecutables del sistema; esto puede causar problemas en sistemas con una estructura de archivos no estándar . Incluso cuando los sistemas tienen rutas bastante estándar, es muy posible que las variantes del mismo sistema operativo tengan ubicaciones diferentes para el intérprete deseado. Python , por ejemplo, podría estar en /usr/bin/python3 , /usr/local/bin/python3 , o incluso en algo como /home/username/bin/python3 si lo instala un usuario común.

Un problema similar existe para el intérprete de comandos POSIX , ya que POSIX solo requería que su nombre fuera sh , pero no exigía una ruta. Un valor común es /bin/sh , pero algunos sistemas como Solaris tienen el intérprete de comandos compatible con POSIX en /usr/xpg4/bin/sh . [ 13 ] En muchos sistemas Linux , /bin/sh es un enlace físico o simbólico a /bin/bash , el intérprete de comandos Bourne Again (BASH). Usar la sintaxis específica de bash mientras se mantiene un shebang que apunta a sh tampoco es portable. [ 14 ]

Debido a esto, a veces es necesario editar la línea shebang después de copiar un script de una computadora a otra, ya que la ruta codificada en el script puede no ser válida en una nueva máquina, dependiendo de la coherencia en la convención anterior de ubicación del intérprete. Por esta razón, y debido a que POSIX no estandariza los nombres de ruta, POSIX no estandariza la característica. [ 15 ] La herramienta GNU Autoconf puede comprobar la compatibilidad del sistema con la macro AC_SYS_INTERPRETER. [ 16 ]

A menudo, el programa /usr/bin/env se puede utilizar para sortear esta limitación introduciendo un nivel de indirección . va seguido de /usr/bin/env , seguido del comando deseado sin la ruta completa, como en este ejemplo:#!

#!/usr/bin/env sh

Esto funciona principalmente porque la ruta /usr/bin/env se usa comúnmente para la utilidad env , e invoca el primer sh que se encuentra en el $PATH del usuario , normalmente /bin/sh .

Este ejemplo en particular (usando sh ) tiene una utilidad limitada: ni /bin/sh ni /usr/bin/env son universales, y un número similar de dispositivos carecen de cada uno. En términos más generales, usar #!/usr/bin/env para cualquier script todavía presenta algunos problemas de portabilidad con OpenServer 5.0.6 y Unicos 9.0.2, que solo tienen /bin/env y no /usr/bin/env .

El uso de #!/usr/bin/env produce una indirección en tiempo de ejecución , lo que puede degradar la seguridad del sistema; por esta razón, algunos comentaristas recomiendan no utilizarlo [ 17 ] en software empaquetado, reservándolo solo para "ejemplos educativos".

División de argumentos

Los argumentos de comando se dividen de diferentes maneras en las distintas plataformas. Algunos sistemas no dividen los argumentos; por ejemplo, al ejecutar el script con la primera línea,

#!/usr/bin/env python3 -c

Todo el texto después del primer espacio se trata como un solo argumento, es decir, python3 -cse pasará como un argumento a /usr/bin/env , en lugar de dos argumentos. Dichos sistemas incluyen Linux [ 18 ] [ 19 ] y Cygwin .

Otro enfoque es el uso de un envoltorio . FreeBSD 6.0 (2005) introdujo una opción -S en su env cuando cambió el comportamiento de lectura de shebang a no división. Esta opción le dice a env que divida la cadena por sí mismo. [ 20 ] La utilidad GNU env desde coreutils 8.30 (2018) también incluye esta característica. [ 21 ] Aunque el uso de esta opción mitiga el problema de portabilidad en el extremo del kernel con la división, agrega el requisito de que env admita esta extensión en particular.

Interpretación de personajes

Otro problema son los scripts que contienen un carácter de retorno de carro inmediatamente después de la línea shebang, quizás como resultado de haber sido editados en un sistema que utiliza saltos de línea de DOS , como Microsoft Windows . Algunos sistemas interpretan el carácter de retorno de carro como parte del comando del intérprete , lo que produce un mensaje de error . [ 22 ]

Número mágico

El shebang es en realidad una instancia legible para humanos de un número mágico en el archivo ejecutable, la cadena de bytes mágica es 0x23 0x21 , la codificación de dos caracteres en ASCII de #! . Este número mágico es detectado por la familia de funciones " exec ", que determina si un archivo es un script o un binario ejecutable. La presencia del shebang dará como resultado la ejecución del ejecutable especificado, generalmente un intérprete para el lenguaje del script. Se ha afirmado [ 23 ] que algunas versiones antiguas de Unix esperan que el shebang normal vaya seguido de un espacio y una barra ( ), pero esto parece ser falso; [ 11 ] más bien, tradicionalmente se han permitido espacios en blanco después del shebang, y a veces se documentan con un espacio, como se describe en el correo electrónico histórico de 1980 a continuación.#! /

Los caracteres shebang se representan mediante los mismos dos bytes en las codificaciones ASCII extendidas , incluida UTF-8 , que se utiliza comúnmente para scripts y otros archivos de texto en los sistemas Unix actuales. Sin embargo, los archivos UTF-8 pueden comenzar con la marca de orden de bytes (BOM) opcional; si la función "exec" detecta específicamente los bytes 0x23 y 0x21 , la presencia de la BOM ( 0xEF 0xBB 0xBF ) antes del shebang impedirá la ejecución del intérprete de scripts. Algunos expertos desaconsejan el uso de la marca de orden de bytes en scripts POSIX (tipo Unix) [ 24 ] , por este motivo y por consideraciones filosóficas y de interoperabilidad más amplias. Además, la marca de orden de bytes no es necesaria en UTF-8, ya que esta codificación no presenta problemas de endianness ; solo sirve para identificar la codificación como UTF-8 [ 24 ] .

Etimología

Un archivo ejecutable que comienza con una directiva de intérprete se llama simplemente script, a menudo precedido por el nombre o la clasificación general del intérprete previsto. El nombre shebang para los dos caracteres distintivos puede provenir de una contracción inexacta de SHArp bang o haSH bang , en referencia a los dos nombres típicos de Unix para ellos. Otra teoría sobre el sh en shebang es que proviene del intérprete de comandos predeterminado sh , que generalmente se invoca con shebang. [ 25 ] Este uso era común en diciembre de 1989, [ 26 ] y probablemente antes.

Historia

La función shebang fue introducida por Dennis Ritchie entre las ediciones 7 y 8 en los Laboratorios Bell. También se añadió a las versiones BSD del Centro de Investigación en Ciencias de la Computación de Berkeley (presente en 2.8BSD [ 27 ] y activada por defecto en 4.2BSD). Dado que la edición 8 de Unix de los Laboratorios Bell de AT&T, y las ediciones posteriores, no se publicaron, la primera aparición ampliamente conocida de esta función fue en BSD.

La ausencia de una directiva de intérprete, pero con soporte para scripts de shell, se evidencia en la documentación de la versión 7 de Unix de 1979, [ 28 ] que describe una funcionalidad del shell Bourne donde los archivos con permisos de ejecución serían manejados de forma especial por el shell, el cual (a veces dependiendo de los caracteres iniciales del script, como ":" o "#") generaría un subshell que interpretaría y ejecutaría los comandos contenidos en el archivo. En este modelo, los scripts solo se comportarían como otros comandos si se llamaran desde dentro de un shell Bourne. Un intento de ejecutar directamente dicho archivo a través de la llamada al sistema exec() del propio sistema operativo fallaría, impidiendo que los scripts se comportaran uniformemente como comandos normales del sistema.

La versión 8 mejoró los scripts de shell.

En versiones posteriores de sistemas tipo Unix, esta inconsistencia se eliminó. Dennis Ritchie introdujo el soporte del kernel para directivas de intérprete en enero de 1980, para la versión 8 de Unix , con la siguiente descripción: [ 29 ]

De uucp jueves 10 de enero 01:37:58 1980 >Desde dmr Jue 10 Ene 04:25:49 1980 remoto desde investigación El sistema se ha modificado de manera que si se ejecuta un archivo comienza con los caracteres mágicos #! , el resto de la línea se entiende ser el nombre de un intérprete para el archivo ejecutado. Anteriormente (y de hecho todavía hoy) la carcasa hacía gran parte de este trabajo; Se ejecutó automáticamente en un archivo de texto con modo ejecutable. cuando el nombre del archivo de texto se escribió como un comando. Al incorporar la instalación al sistema se obtiene lo siguiente: beneficios. 1) Hace que los scripts de shell se parezcan más a archivos ejecutables reales, porque pueden ser el sujeto de 'ejecución'. 2) Si haces un 'ps' mientras se está ejecutando dicho comando, es real En lugar de 'sh' aparece el nombre. Asimismo, la contabilidad se realiza sobre la base del nombre real. 3) Los scripts de shell pueden ser set-user-ID. [ a ] 4) Es más sencillo tener disponibles carcasas alternativas; Por ejemplo, si te gusta el Berkeley csh, no hay duda de que ¿Qué intérprete de comandos debe interpretar un archivo? 5) Permitirá que otros intérpretes se integren con mayor fluidez. Para aprovechar esta maravillosa oportunidad, poner #! /bin/sh en el margen izquierdo de la primera línea de sus scripts de shell. Los espacios en blanco después de ! están bien. Use la ruta completa (no se realiza ninguna búsqueda). En este momento, toda la línea está restringida a 16 caracteres, pero Este límite se incrementará.

Característica de script de shell sin nombre

Sin embargo, el creador de la función no le dio un nombre: [ 31 ]

De: "Ritchie, Dennis M (Dennis)** CTR **" <dmr@[redacted]> Para: <[redacted]@ talisman.org > Fecha: Jue, 19 Nov 2009 18:37:37 -0600 Asunto: RE: ¿Cómo llamas a tu línea #!<algo> ? No recuerdo que le hayamos puesto un nombre propio. Fue bastante tarde cuando entró, creo que yo La idea me la dio alguien en una de las conferencias de la UCB. en Berkeley Unix; puede que haya sido uno de los primeros en En realidad lo instalé, pero fue una idea que tuve. de otro lugar. En cuanto al nombre: probablemente algo descriptivo como "hash-bang" aunque esto tiene un sabor específicamente británico, pero En cualquier caso, no recuerdo haber usado particularmente un apodo cariñoso. para la construcción. 

El soporte del kernel para las directivas del intérprete se extendió a otras versiones de Unix, y una implementación moderna se puede ver en el código fuente del kernel de Linux en fs/binfmt_script.c . [ 32 ]

Este mecanismo permite utilizar scripts en prácticamente cualquier contexto en el que se puedan usar programas compilados normales, incluyendo programas de sistema completos e incluso intérpretes de otros scripts. Sin embargo, cabe mencionar que algunas versiones iniciales del soporte del kernel limitaban la longitud de la directiva del intérprete a aproximadamente 32 caracteres (solo 16 en su primera implementación), no separaban el nombre del intérprete de los parámetros de la directiva o presentaban otras peculiaridades. Además, algunos sistemas modernos permiten restringir o deshabilitar todo el mecanismo por motivos de seguridad (por ejemplo, en muchos sistemas se ha deshabilitado el soporte para establecer el ID de usuario en los scripts).

Cabe destacar que, incluso en sistemas con soporte completo del kernel para el número mágico #!, algunos scripts que carecen de directivas de intérprete (aunque generalmente requieren permiso de ejecución) aún se pueden ejecutar gracias al manejo de scripts heredado del intérprete de comandos Bourne, que todavía está presente en muchos de sus descendientes modernos. En ese caso, los scripts son interpretados por el intérprete de comandos predeterminado del usuario.

Véase también

Notas

  1. La función setuid está deshabilitada en la mayoría de los sistemas operativos modernos tras darse cuenta de que se puede explotar una condición de carrera para cambiar el script mientras se está procesando. [ 30 ]

Referencias

  1. "Guía avanzada de scripting de Bash: Capítulo 2. Comenzando con un Sha-Bang" . Archivado del original el 10 de diciembre de 2019. Consultado el 10 de diciembre de 2019 .
  2. Cooper, Mendel (5 de noviembre de 2010). Guía avanzada de scripting Bash 5.3 Volumen 1. lulu.com. pág. 5. ISBN  978-1-4357-5218-4.
  3. MacDonald, Matthew (2011). HTML5: El manual que faltaba . Sebastopol, California: O'Reilly Media . pág. 373. ISBN  978-1-4493-0239-9.
  4. Lutz, Mark (septiembre de 2009). Aprendiendo Python (4.ª ed.). O'Reilly Media . pág. 48. ISBN   978-0-596-15806-4.
  5. Guelich, Gundavaram y Birznieks, Scott, Shishir y Gunther (29 de julio de 2000). Programación CGI con PERL (2.ª ed.). O'Reilly Media . pág . 358. ISBN   978-1-56592-419-2.{{cite book}}: CS1 maint: varios nombres: lista de autores ( enlace )
  6. ^ Mentira Hetland, Magnus (4 de octubre de 2005). Principiantes en Python: de principiante a profesional . Presione. pag. 21.ISBN  978-1-59059-519-0.
  7. Schitka, John (24 de diciembre de 2002). Guía Linux+ para la certificación Linux . Course Technology. pág. 353. ISBN  978-0-619-13004-6.
  8. 1 2 "execve(2) - Página man de Linux" . Consultado el 21 de octubre de 2010 .
  9. "SRFI 22" .
  10. "Python - La línea shebang de Python3 no funciona como se esperaba" .
  11. 1 2 Maschek, Sven (30 de diciembre de 2010). "La magia de #!, detalles sobre el mecanismo shebang/hash-bang: ¿Es necesario dejar un espacio en blanco después de #!?" . www.in-ulm.de . Consultado el 18 de enero de 2024 .
  12. si lo permiten los bits de permisos de ejecución del archivo
  13. "Especificaciones básicas de The Open Group, número 7" . 2008. Consultado el 5 de abril de 2010 .
  14. "pixelbeat.org: Errores comunes en scripts de shell" . Es mucho mejor probar los scripts directamente en un shell compatible con POSIX si es posible. La opción `bash --posix` no es suficiente, ya que aún acepta algunas peculiaridades de bash.
  15. "Capítulo 2. Lenguaje de comandos de shell" , Especificaciones base de The Open Group (IEEE Std 1003.1-2017) (Edición 7 ), IEEE, 2018 [2008], Si la primera línea de un archivo de comandos de shell comienza con los caracteres "#!", los resultados no están especificados. 
  16. Autoconf , Free Software Foundation, Macro: AC_SYS_INTERPRETER: Comprueba si el sistema admite el inicio de scripts con una línea del tipo '#!/bin/sh' para seleccionar el intérprete que se utilizará para el script.
  17. "¿Qué pasa con #!/usr/bin/env bash?" . Consultado el 6 de marzo de 2024 .
  18. "Página de manual de execve(2)" ., sección "Scripts del intérprete"
  19. "Comportamiento de /usr/bin/env" . Mail-index.netbsd.org. 9 de noviembre de 2008. Consultado el 18 de noviembre de 2010 .
  20. Manual de comandos generales de FreeBSDenv(1)  
  21. "invocación de env" . GNU Coreutils . Consultado el 11 de febrero de 2020 .
  22. "El retorno de carro provoca que bash falle" . 8 de noviembre de 2013.
  23. "Manual de GNU Autoconf v2.57, Capítulo 10: Programación de shell portátil" . Archivado del original el 18 de enero de 2008. Consultado el 14 de mayo de 2020 .
  24. 1 2 "Preguntas frecuentes sobre UTF-8, UTF-16, UTF-32 y BOM: ¿Puede una secuencia de datos UTF-8 contener el carácter BOM (en formato UTF-8)? Si es así, ¿puedo asumir que los bytes UTF-8 restantes están en orden big-endian?" . Unicode . Consultado el 10 de noviembre de 2023 .
  25. "Entrada del archivo de jerga para shebang" . Catb.org . Consultado el 16 de junio de 2010 .
  26. Wall, Larry . "Perl no entendió los scripts setuid que tenían un espacio en la primera línea entre el shebang y el nombre del intérprete" . USENET .
  27. McKusick, Marshall Kirk (agosto de 1998), "2.8/usr/kernel/sys/sys/sys1.c" , The CSRG Archives CD-ROM 1: Berkeley Systems 1978-1986 , línea 43, archivado del original el 8 de julio de 2017,# define SCRMAG '#!'
  28. Sistema de tiempo compartido Unix: Manual del programador Unix (PDF) , vol. 2A (séptima edición), enero de 1979, archivado del original (PDF) el 5 de junio de 2001  
  29. McKusick, Marshall Kirk (agosto de 1998), "4.0/usr/src/sys/newsys/sys1.c" , The CSRG Archives CD-ROM 1: Berkeley Systems 1978-1986 , archivado del original el 8 de julio de 2017.
  30. Gilles. "linux - ¿Por qué está deshabilitado SUID para los scripts de shell pero no para los binarios?" . Information Security Stack Exchange .
  31. Richie, Dennis. "Dennis Ritchie y Hash-Bang" . Talisman.org . Consultado el 3 de diciembre de 2020 .
  32. Rubini, Alessandro (31 de diciembre de 1997). "Jugando con formatos binarios" . Linux Journal . Consultado el 1 de enero de 2015 .
  • Detalles sobre el mecanismo shebang en varias versiones de Unix.
  • #! - La verdad sobre Unix hasta donde yo sé (un enfoque más genérico)
  • Artículo sobre FOLDOC shebang