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/sh
en los scripts de shell escritos en distribuciones de Ubuntu?
shebang
Respuestas:
#!/bin/sh
deberí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/sh
supone 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/sh
shell.#!/bin/sh
normalmente es solo un enlace ahora, ya que el shell Bourne ya no se mantiene. En muchos sistemas Unix/bin/sh
habrá un enlace/bin/ksh
o/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 comosh
, 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
bash
se invoca en modo POSIX, todavía permitirá algunas cosas que no sean POSIX, como[[
matrices y más. Esas cosas pueden fallar en un nobash
sistema.fuente
/bin/ash
.#! /
lugar de solo#!
.Lo tienes al revés.
/bin/sh
Casi nunca es un shell Bourne en estos días, y es cuando es así que tienes un problema cuando usas un#! /bin/sh
she-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/sh
a 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
,yash
y algunospdksh
derivados permiten un modo compatible con POSIX Cuando se invoca comosh
y 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 POSIXsh
(como parte de la certificación macOS).Cuando escribe un script con un
#! /bin/sh -
she-bang, debe usar unash
sintaxis 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 esesh
inté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/sh
ella-bang, su problema principal sería los sistemas en los que/bin/sh
es 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:Por cierto, Ubuntu
/bin/sh
no esbash
por defecto. Es endash
estos días, un shell basado en NetBSDsh
, 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 entrebash
ydash
para/bin/sh
condpkg-reconfigure dash
) 4 .sh
los 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 enzsh
lash
emulación obosh
(probablemente no,ksh93
ni losyash
que no tienenlocal
incorporado (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/bin
directorio pero probablemente no le importa), y eso generalmente es unsh
intérprete POSIX (y en casos raros un shell Bourne (no estándar) )Pero
sh
es 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ánbash
. 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 sibash
alguno de esos otros shells se instalará en/bin
o en otro lugar (por lo general, se encuentra en/usr/local/bin
BSD 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/executable
no 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/file
consome-optional-arg
, la ruta del script y los argumentos originales como argumentos. Puedes hacer esa primera línea#! /bin/echo test
para ver qué está pasando:Cuando se usa en
/bin/sh -
lugar de/bin/echo test
, el núcleo se ejecuta/bin/sh - ./myscript foo
,sh
interpreta el código de contenido almacenadomyscript
e 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/sh
shell 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 (elsh
lenguaje POSIX no es completamente compatible con versiones anteriores del shell Bourne) y (al menos para las implementaciones de escritorio y servidor completo) tienen POSIX ensh
otro lugar (en/usr/xpg4/bin/sh
, basado en ksh88), pero eso cambió en Solaris 11, donde/bin/sh
ahora es ksh93. Los otros son en su mayoría difuntos.² El
/bin/sh
de MacOS / X solía serzsh
, pero luego cambió abash
. Nozsh
es el enfoque principal para ser utilizado como unash
implementación POSIX . Sush
modo es principalmente poder incrustar o invocar (source
)sh
código POSIX enzsh
scripts³ Recientemente, @schily extendió el shell OpenSolaris (basado en el shell SVR4, basado en el shell Bourne) para que sea compatible con POSIX,
bosh
pero no estoy al tanto de que todavía se utiliza en ningún sistema. Junto conksh88
eso lo convierte en un segundo shell compatible con POSIX basado en el código del shell Bourne4 En versiones anteriores, también podría usar
mksh
o sulksh
encarnació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)fuente
exec sh "$0" "$@"
después de configurar elPATH
? Eso debería comenzarsh
desde el lugar correcto, habría pensado.$PATH
.$(...)
, modos emacs / vi, expansiones tilde / brace (aquellas inicialmente desde csh), fc, tipografía, alias , sintaxis de la función de estilo ksh ...Sí, puede usarlo
#!/bin/sh
en 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 sebash
comporte (más o menos) como losh
haría. Aquí hay un sistema Centos7, por ejemplo, que se vinculash
abash
:También podría usarlo
#!/bin/bash
si está escribiendo unabash
secuencia de comandos solo para ese sistema y desea usarbash
funciones. Sin embargo, tales scripts sufrirán problemas de portabilidad, por ejemplo, en OpenBSD, dondebash
solo 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/sh
script estrictamente POSIX debería ser más portátil.fuente
sh
, Bash entra en modo POSIX después de leer los archivos de inicio". - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode#!/bin/bash
precisamente para poder aprovechar las características que no son POSIX./bin/sh
es un enlace simbólicobash
, ¿es correcto? Sin embargo, estoy seguro de que en CentOS lo es.bash
. El binario sabe qué nombre se usó para invocarlo, y cuando se llamash
actúa como el Bourne de la vieja escuelash
.Tu preguntaste
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
)fuente
Los "#!" el comentario no siempre usa
/bin/bash
o/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/sh
y#!/bin/bash
es que/bin/sh
no 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
.fuente
Perdón por verter un poco de agua fría en todas esas excelentes respuestas que dicen que
/bin/sh
está 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/sh
enlace, 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/sh
con este camino no está ordenada por el estándar :fuente
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)?/bin/sh