¿Es correcto usar / bin / sh en el hashbang si el shell Bourne no está disponible en una distribución?

15

En general, los scripts de shell contienen el siguiente comentario en la primera línea del archivo de secuencia de comandos: #!/bin/sh. Según las investigaciones que hice, esto se llama "hash bang" y es un comentario convencional. Este comentario informa a Unix que Bourne Shell ejecuta este archivo en el directorio /bin.

Mi pregunta comienza en ese punto. Hasta ahora no he visto este comentario como #!/bin/bash. Es siempre #!/bin/sh. Sin embargo, las distribuciones de Ubuntu no tienen el programa Bourne Shell. Tienen el Bourne Again Shell (bash).

En ese punto, ¿es correcto colocar el comentario #!/bin/shen los scripts de shell escritos en distribuciones de Ubuntu?

Goktug
fuente
44
AKA shebang, en.wikipedia.org/wiki/Shebang_(Unix)
K7AAY
1
Vea mi respuesta a esta pregunta predeterminada del servidor: #! / Bin / sh vs #! / Bin / bash para obtener la máxima portabilidad .
Gordon Davisson el
Más comúnmente llamadoshebang
fpmurphy

Respuestas:

16

#!/bin/shdebería funcionar en todas las distribuciones Unix y similares a Unix. Generalmente se considera el hashbang más portátil siempre que su script se mantenga compatible con POSIX. Se /bin/shsupone que el shell es un shell que implementa el estándar de shell POSIX, independientemente de cuál sea el shell real que se hace pasar por el /bin/shshell.


#!/bin/shnormalmente es solo un enlace ahora, ya que el shell Bourne ya no se mantiene. En muchos sistemas Unix /bin/shhabrá un enlace /bin/ksho /bin/ash, en muchos sistemas Linux basados ​​en RHEL, será un enlace /bin/bash, sin embargo, en Ubuntu y en muchos sistemas basados ​​en Debian es un enlace /bin/dash. Todos los shells, cuando se invocan como sh, ingresarán al modo de compatibilidad POSIX.

Sin embargo, el hashbang es un marcador de posición importante porque permite una portabilidad mucho mayor que otros métodos, siempre que su script cumpla estrictamente con POSIX (repetido para enfatizar la importancia).

Nota: cuando bashse invoca en modo POSIX, todavía permitirá algunas cosas que no sean POSIX, como [[matrices y más. Esas cosas pueden fallar en un no bashsistema.

Jesse_b
fuente
3
"en Ubuntu es un enlace a / bin / dash" y, en general, a otros sistemas basados ​​en Debian. IIRC en FreeBSD / GhostBSD también es un enlace simbólico /bin/ash.
Sergiy Kolodyazhnyy
Para ser totalmente portátil, coloque un espacio entre el shebang y la ruta (absoluta) del intérprete. Algunos sistemas buscan en #! /lugar de solo #!.
Simon Richter
55
@SimonRichter Una referencia para esto sería agradable de ver.
Kusalananda
@SergiyKolodyazhnyy La versión instalada de sh en FreeBSD es ash y no un enlace simbólico.
Rob el
2
@Kusalananda, hmm, esta página dice que esto es un mito, por lo que probablemente se pueda ignorar.
Simon Richter
12

Lo tienes al revés. /bin/shCasi nunca es un shell Bourne en estos días, y es cuando es así que tienes un problema cuando usas un #! /bin/shshe-bang.

El shell Bourne fue un shell escrito a finales de los años 70 y reemplazó al shell Thompson anterior (también llamado sh). A principios de los años 80, David Korn escribió algunas extensiones para el shell Bourne, reparó algunos de los errores y torpezas de diseño (e introdujo algunos) y lo llamó el shell Korn.

A principios de los años 90, POSIX especificó el sh lenguaje basado en un subconjunto del shell Korn y la mayoría de los sistemas ahora han cambiado /bin/sha Korn shell o a un shell compatible con esa especificación. En el caso de los BSD, cambiaron gradualmente su /bin/sh, inicialmente (después de que ya no pudieron usar el shell Bourne por razones de licencia) el shell Almquist, un clon del shell Bourne con algunas extensiones ksh, por lo que se volvió compatible con POSIX.

Hoy, todos los sistemas POSIX tienen un shell llamado sh(más a menudo, pero no necesariamente /bin, POSIX no especifica la ruta de las utilidades que especifica) que es en su mayoría compatible con POSIX. Generalmente se basa en ksh88, ksh93, pdksh, bash, ash o zsh², pero no en el shell Bourne ya que el shell Bourne nunca fue compatible con POSIX³. Algunas de esas conchas ( bash, zsh, yashy algunos pdkshderivados permiten un modo compatible con POSIX Cuando se invoca como shy son menos compatible de otra manera).

bash(la respuesta de GNU al shell Korn) es en realidad el único shell de código abierto (y se podría decir que solo se mantiene actualmente ya que los otros generalmente se basan en ksh88, que no ha recibido ninguna característica nueva desde los años 90) que ha sido certificado como ser compatible con POSIX sh(como parte de la certificación macOS).

Cuando escribe un script con un #! /bin/sh -she-bang, debe usar una shsintaxis estándar (y también debe usar la sintaxis estándar para las utilidades utilizadas en ese script si desea ser portátil, no es solo el shell lo que está involucrado al interpretar un shell script), entonces no importa qué implementación de ese shintérprete de sintaxis estándar se use ( ksh, bash...).

No importa que esos shells tengan extensiones sobre el estándar siempre que no los use. Es como escribir código C, siempre que escriba código C estándar y no use extensiones de un compilador (como gcc) u otro, su código debe compilarse bien, independientemente de la implementación del compilador, siempre que el compilador sea compatible.

Aquí, con su #! /bin/shella-bang, su problema principal sería los sistemas en los que /bin/shes el shell Bourne que por ejemplo no es compatible con características estándar como $((1+1)), $(cmd), ${var#pattern}... En cuyo caso es posible que necesite soluciones temporales como:

#! /bin/sh -
if false ^ true; then
  # in the Bourne shell, ^ is an alias for |, so false ^ true returns
  # true in the Bourne shell and the Bourne shell only.
  # Assume the system is Solaris 10 (older versions are no longer maintained)
  # You would need to adapt if you need to support some other system
  # where /bin/sh is the Bourne shell.
  # We also need to fix $PATH as the other utilities in /bin are
  # also ancient and not POSIX compatible.
  PATH=`/usr/xpg6/bin/getconf PATH`${PATH:+:}$PATH || exit
  export PATH
  exec /usr/xpg4/bin/sh "$0" "$@"
  # that should give us an environment that is mostly  compliant
  # to the Single UNIX Specification version 3 (POSIX.2004), the
  # latest supported by Solaris 10.
fi
# rest of the script

Por cierto, Ubuntu /bin/shno es bashpor defecto. Es en dashestos días, un shell basado en NetBSD sh, basado en el shell Almquist, que en su mayoría es compatible con POSIX, excepto que no admite caracteres de varios bytes. En Ubuntu y otros sistemas basados ​​en Debian, puede elegir entre bashy dashpara /bin/shcon dpkg-reconfigure dash) 4 . shlos scripts enviados con Debian deberían funcionar igual en ambos shells, ya que están escritos en el estándar de política de Debian (un superconjunto del estándar POSIX). Probablemente encontrará que también funcionan bien en zshla shemulación o bosh(probablemente no, ksh93ni los yashque no tienen localincorporado (requerido por la política de Debian pero no POSIX)).

Todos los sistemas en alcance en unix.stackexchange.com tienen un POSIX en sh alguna parte. La mayoría de ellos tienen un /bin/sh(puede encontrar algunos muy raros que no tienen un /bindirectorio pero probablemente no le importa), y eso generalmente es un shintérprete POSIX (y en casos raros un shell Bourne (no estándar) )

Pero shes el único ejecutable de intérprete de shell que puede estar seguro de encontrar en un sistema. Para los otros shells, puede estar seguro de que macOS, Cygwin y la mayoría de las distribuciones de GNU / Linux tendrán bash. Los sistemas operativos derivados de SYSV (Solaris, AIX ...) generalmente tendrán ksh88, posiblemente ksh93. OpenBSD, MirOS tendrá una derivada pdksh. macOS tendrá zsh. Pero fuera de eso, no habrá garantía. No hay garantía de si bashalguno de esos otros shells se instalará en /bino en otro lugar (por lo general, se encuentra en /usr/local/binBSD cuando se instala, por ejemplo). Y, por supuesto, no hay garantía de la versión del shell que se instalará.

Tenga en cuenta que #! /path/to/executableno es una convención , es una característica de todos los núcleos tipo Unix ( introducidos a principios de los años 80 por Dennis Ritchie ) que permite ejecutar archivos arbitrarios al especificar la ruta del intérprete en una primera línea que comienza #!. Puede ser cualquier ejecutable.

Cuando ejecuta un archivo cuya primera línea comienza #! /some/file some-optional-arg, el núcleo termina ejecutándose /some/filecon some-optional-arg, la ruta del script y los argumentos originales como argumentos. Puedes hacer esa primera línea #! /bin/echo testpara ver qué está pasando:

$ ./myscript foo
test ./myscript foo

Cuando se usa en /bin/sh -lugar de /bin/echo test, el núcleo se ejecuta /bin/sh - ./myscript foo, shinterpreta el código de contenido almacenado myscripte ignora esa primera línea, ya que es un comentario (comienza con #).


¹ Probablemente el único sistema actual en el que cualquiera de nosotros se encontrará con un /bin/shshell basado en Bourne es Solaris 10. Solaris es uno de los pocos Unices que decidió mantener un shell Bourne allí para la compatibilidad con versiones anteriores (el shlenguaje POSIX no es completamente compatible con versiones anteriores del shell Bourne) y (al menos para las implementaciones de escritorio y servidor completo) tienen POSIX en shotro lugar (en /usr/xpg4/bin/sh, basado en ksh88), pero eso cambió en Solaris 11, donde /bin/shahora es ksh93. Los otros son en su mayoría difuntos.

² El /bin/shde MacOS / X solía serzsh , pero luego cambió a bash. No zshes el enfoque principal para ser utilizado como una shimplementación POSIX . Su shmodo es principalmente poder incrustar o invocar ( source) shcódigo POSIX en zshscripts

³ Recientemente, @schily extendió el shell OpenSolaris (basado en el shell SVR4, basado en el shell Bourne) para que sea compatible con POSIX, boshpero no estoy al tanto de que todavía se utiliza en ningún sistema. Junto con ksh88eso lo convierte en un segundo shell compatible con POSIX basado en el código del shell Bourne

4 En versiones anteriores, también podría usar mksho su lkshencarnación más POSIX . Ese es el shell MirOS (anteriormente MirBSD) basado en pdksh, basado en el shell Forsyth (otra reimplementación del shell Bourne)

Stéphane Chazelas
fuente
Algo menor (sobre el código de shell a mitad de la respuesta): ¿no debería usarlo justo exec sh "$0" "$@"después de configurar el PATH? Eso debería comenzar shdesde el lugar correcto, habría pensado.
Kusalananda
1
@Kusalananda, eso debería funcionar, pero es más arriesgado, ya que podríamos terminar en un bucle sin fin si algo anda mal (como sh con permisos incorrectos, getconf modificado ...). De todos modos, el resto es específico de Solaris 10, por lo que también podríamos codificar todo, incluido el contenido de $PATH.
Stéphane Chazelas
Cualquier cita para OSX usando ksh como su shell POSIX. Su shell predeterminado solía ser tcsh, pero no recuerdo que bash no se usara especialmente, ya que Korn Shell no era de código abierto hasta que salió OSX
user151019
1
@ Mark, no dije que OSX alguna vez usó ksh. Dije que solía ser zsh y cambiaron a bash (una compilación especial de bash).
Stéphane Chazelas
1
@fpmurphy, si nos fijamos en las primeras versiones, bash ya estaba del lado de ksh donde ksh no era compatible con el shell Bourne. Si bien tuvo que esperar hasta bash2 para llegar al mismo nivel de características que ksh88, bash inicialmente ya tenía varias de las extensiones de ksh como $(...), modos emacs / vi, expansiones tilde / brace (aquellas inicialmente desde csh), fc, tipografía, alias , sintaxis de la función de estilo ksh ...
Stéphane Chazelas
8

Sí, puede usarlo #!/bin/shen un script porque /bin/sh(con suerte) está previsto en dichos sistemas, generalmente a través de un enlace de algún tipo que hace que se bashcomporte (más o menos) como lo shharía. Aquí hay un sistema Centos7, por ejemplo, que se vincula sha bash:

-bash-4.2$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Dec  4 16:48 /bin/sh -> bash
-bash-4.2$ 

También podría usarlo #!/bin/bashsi está escribiendo una bashsecuencia de comandos solo para ese sistema y desea usar bashfunciones. Sin embargo, tales scripts sufrirán problemas de portabilidad, por ejemplo, en OpenBSD, donde bashsolo se instala si el administrador se toma la molestia de instalarlo (yo no) y luego se instala /usr/local/bin/bash, no /bin/bash. Un #!/bin/shscript estrictamente POSIX debería ser más portátil.

thrig
fuente
Tenga en cuenta esto: "Cuando se invoca como sh, Bash entra en modo POSIX después de leer los archivos de inicio". - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode
glenn jackman el
2
Cuando escribo scripts para servidores RHEL en mi trabajo, lo uso #!/bin/bashprecisamente para poder aprovechar las características que no son POSIX.
Monty Harder
@MontyHarder IIRC en RHEL /bin/shes un enlace simbólico bash, ¿es correcto? Sin embargo, estoy seguro de que en CentOS lo es.
Sergiy Kolodyazhnyy
1
@SergiyKolodyazhnyy Sí, en el servidor RHEL que acabo de comprobar, es un enlace simbólico a bash. El binario sabe qué nombre se usó para invocarlo, y cuando se llama shactúa como el Bourne de la vieja escuela sh.
Monty Harder
6

Tu preguntaste

¿es correcto colocar el comentario #! / bin / sh en los scripts de shell escritos en distribuciones de ubuntu?

La respuesta depende de lo que escriba en el script de shell.

  • Si usa estrictamente scripts portátiles compatibles con POSIX y no usa ningún comando específico de bash, puede usarlo /bin/sh.

  • Si sabe que solo está utilizando el script en una máquina con bash, y desea usar la sintaxis específica de bash, entonces debe usar/bin/bash

  • Si desea estar seguro de que el script funcionará en una variedad de máquinas Unix, entonces debe usar solo la sintaxis compatible con POSIX, y/bin/sh

  • Si usted usa con regularidad otra línea de comandos (por ejemplo, ksh , zsh o tcsh ), y desea utilizar esa sintaxis en el script, entonces usted debe utilizar el intérprete apropiada (como /bin/ksh93, /bin/zsh, o /bin/tcsh)

Stobor
fuente
3

Los "#!" el comentario no siempre usa /bin/basho /bin/sh. Simplemente enumera lo que debería ser el intérprete, no solo para los scripts de shell. Por ejemplo, mis scripts de Python generalmente comienzan con #!/usr/bin/env python.

Ahora la diferencia entre #!/bin/shy #!/bin/bashes que /bin/shno siempre es un enlace simbólico a /bin/bash. A menudo pero no siempre. Ubuntu es una notable excepción aquí. He visto scripts que funcionan bien en CentOS pero fallan en Ubuntu porque el autor usó la sintaxis específica de bash con #!/bin/sh.

aragaer
fuente
1

Perdón por verter un poco de agua fría en todas esas excelentes respuestas que dicen que /bin/shestá presente en todos los sistemas Unix, está presente, excepto en el sistema Unix más utilizado de todos los tiempos: Android.

Android tiene su shell /system/bin/sh, y generalmente no hay forma de hacer un /bin/shenlace, incluso en un sistema rooteado (debido a la forma en que el sistema está bloqueado mediante el uso de selinux y capacidades (7) conjuntos de límites).

Para aquellos que dirán que Android no es compatible con POSIX: tampoco lo son la mayoría de las distribuciones de Linux y BSD. Y la existencia de /bin/shcon este camino no está ordenada por el estándar :

Las aplicaciones deben tener en cuenta que PATHno se puede suponer que el estándar para el shell sea /bin/sho /usr/bin/sh, y debe determinarse mediante la interrogación del PATHdevuelto por getconf PATH, asegurando que el nombre de ruta devuelto sea un nombre de ruta absoluto y no un shell incorporado.

Mosvy
fuente
Si bien todos los sistemas que intentan ser compatibles con POSIX tienen numerosos errores de conformidad (incluidos los certificados), Android (y la mayoría de los otros sistemas integrados como su enrutador o sistema operativo de bombilla) no tienen la intención de ser compatibles con POSIX. Android está fuera de tema aquí, excepto cuando se trata de su interfaz POSIX.
Stéphane Chazelas
@Christopher, getconf¿ cuál ? Por ejemplo, en Solaris 11.4, ¿sería ese /usr/bin? ¿El que está en /usr/xpg4/bin(para el cumplimiento de SUSv2), el que está en /usr/xpg6/bin(para el cumplimiento de SUSv3)? /usr/xpg7/bin(para SUSv4)?
Stéphane Chazelas
@ StéphaneChazelas si estamos dispuestos a juzgar las intenciones, creo que puedo desenterrar fácilmente algunas citas de Linus Torvalds o Theo de Raadt en el sentido de que no les importa mucho POSIX ;-) Y la mayoría de los sistemas integrados se basan en Linux + busybox, que apenas es menos compatible con POSIX que el típico sistema tipo Unix. Y a) Android no es realmente un sistema "incrustado" yb) un sistema Android podría ser compatible con POSIX sin tener un shell en /bin/sh
mosvy
1
@mosvy, lo que dices es mayormente cierto. Pero Torvalds solo puede hablar por el kernel de Linux. Chet Ramey se preocupa por el cumplimiento de POSIX para bash, RedHat se preocupa por el cumplimiento de POSIX (patrocinan al grupo Austin y se sientan en sus reuniones grupales, mantienen una gran cantidad del software GNU). La idea es que POSIX es el único estándar que observan la mayoría de los sistemas tipo Unix. Los usuarios se preocupan por la compatibilidad con POSIX, ya que hace que sea más fácil tener un software portátil para diferentes sistemas. No es ideal, pero es mejor que nada. Android tiene su propia API de programación, POSIX no es realmente una preocupación allí.
Stéphane Chazelas