Supongamos que el shell predeterminado para mi cuenta es zsh, pero abrí el terminal y activé bash y ejecuté un script llamado prac002.sh
, ¿qué intérprete de shell se usaría para ejecutar el script, zsh o bash? Considere el siguiente ejemplo:
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % sudo cat /etc/passwd | grep papagolf
[sudo] password for papagolf:
papagolf:x:1000:1001:Rex,,,:/home/papagolf:/usr/bin/zsh
# papagolf's default shell is zsh
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % bash
# I fired up bash. (See that '%' prompt in zsh changes to '$' prompt, indicating bash.)
papagolf@Sierra:~/My Files/My Programs/Learning/Shell$ ./prac002.sh
Enter username : Rex
Rex
# Which interpreter did it just use?
** EDITAR: ** Aquí está el contenido del guión
papagolf@Sierra ~/My Files/My Programs/Learning/Shell % cat ./prac002.sh
read -p "Enter username : " uname
echo $uname
. prac002.sh
, suponiendo que su script esté en el directorio actual.. ./prac002.sh
y se ejecutará con el shell actual, es decir, dot (.
), espacio () seguido de la ruta de su script. Se llama dot-sourcing de su script. ;-)Respuestas:
Debido a que el script no comienza con una
#!
línea shebang que indica qué intérprete usar, POSIX dice que :Esa redacción es un poco ambigua, y las diferentes conchas tienen diferentes interpretaciones.
En este caso, Bash ejecutará el script usándose a sí mismo . Por otro lado, si lo ejecutó desde zsh, zsh usaría
sh
(lo que sea que esté en su sistema) en su lugar.Puede verificar ese comportamiento para este caso agregando estas líneas al script:
Notarás que, desde Bash, la primera línea emite tu versión, mientras que la segunda nunca dice nada, sin importar qué shell uses.
/bin/sh
es, digamos,dash
entonces ninguna línea generará nada cuando el script se ejecute desde zsh o dash./bin/sh
es un enlace a Bash, verá la salida de la primera línea en todos los casos./bin/sh
es una versión diferente de Bash de la que estaba usando directamente, verá resultados diferentes cuando ejecute el script desde bash directamente y desde zsh.El
ps -p $$
comando de la respuesta de rools también mostrará información útil sobre el comando que el shell usó para ejecutar el script.fuente
execl()
llamada ocurre cuando un script de shell no contiene un shebang y se ejecuta comoscriptname
? ¿No sucede cuando un script de shell se ejecuta comobash scriptname
? ¿No sucede cuando un script de shell contiene un shebang y se ejecuta comoscriptname
?Dado que el archivo no es de ninguno de los tipos de ejecutables reconocidos por el sistema, y suponiendo que tenga el permiso para ejecutar ese archivo, la
execve()
llamada al sistema generalmente fallará con un errorENOEXEC
( no ejecutable ).Lo que sucede entonces depende de la aplicación y / o función de biblioteca utilizada para ejecutar el comando.
Puede ser, por ejemplo, un shell, la función
execlp()
/execvp()
libc.La mayoría de las otras aplicaciones usarán cualquiera de ellas cuando ejecuten un comando. Invocarán un shell, por ejemplo, mediante la
system("command line")
función libc, que normalmente invocarásh
para analizar esa línea de comando (cuya ruta se puede determinar en el momento de la compilación (como/bin/sh
vs/usr/xpg4/bin/sh
en Solaris)), o invocará el shell almacenado$SHELL
por ellos mismos comovi
con su!
comando,xterm -e 'command line'
y muchos otros comandos (su user -c
invocarán el shell de inicio de sesión del usuario en lugar de$SHELL
).En general, un archivo de texto sin shebang que no comienza
#
se considera unsh
script. Sinsh
embargo, cuál es variará.execlp()
/execvp()
, alexecve()
regresarENOEXEC
normalmente invocarásh
en él. Para los sistemas que tienen más de unosh
porque pueden ajustarse a más de un estándar, losh
que se determinará generalmente en el momento de la compilación (de la aplicación usandoexecvp()
/execlp()
mediante la vinculación de un blob de código diferente que se refiere a una ruta diferente ash
). Por ejemplo, en Solaris, será/usr/xpg4/bin/sh
(un estándar, POSIXsh
) o/bin/sh
(el shell Bourne (un shell anticuado) en Solaris 10 y versiones anteriores, ksh93 en Solaris 11).Cuando se trata de conchas, hay mucha variación.
bash
, AT&Tksh
, el shell Bourne generalmente interpretará la secuencia de comandos ellos mismos (en un proceso secundario a menos queexec
se use) después de haber simulado unexecve()
, que desarma todas las variables no exportadas, cierra todos los archivos close-on-exec, elimina todas las trampas personalizadas, alias, funciones ... (bash
interpretará el script ensh
modo).yash
se ejecutará en sí (consh
comoargv[0]
lo que ensh
modo) para interpretarlo.zsh
,pdksh
,ash
Cáscaras basados típicamente invocarsh
(el camino de los cuales determina en tiempo de compilación).Para
csh
ytcsh
(y elsh
de algunos BSD anteriores), si el primer carácter del archivo es#
, entonces se ejecutarán para interpretarlo, y de losh
contrario. Eso se remonta a un tiempo anterior al shebang dondecsh
reconocía#
como comentarios pero no el shell Bourne, por lo que#
era una pista de que era un script csh.fish
(al menos la versión 2.4.0), solo devuelve un error siexecve()
falla (no intenta tratarlo como un script).Algunos shells (como
bash
AT&Tksh
) primero intentarán determinar heurísticamente si el archivo probablemente sea un script o no. Por lo tanto, es posible que algunos shells se nieguen a ejecutar un script si tiene un carácter NUL en los primeros bytes.También tenga en cuenta que si
execve()
falla con ENOEXEC pero el archivo tiene una línea shebang, algunos shells intentan interpretar esa línea shebang ellos mismos.Entonces, algunos ejemplos:
$SHELL
es/bin/bash
,xterm -e 'myscript with args'
habrámyscript
interpretado porbash
ensh
modo. Mientras que conxterm -e myscript with args
,xterm
se usaráexecvp()
para que el guión sea interpretado porsh
.su -c myscript
en Solaris 10 donderoot
el shell de inicio de sesión es/bin/sh
y/bin/sh
es el shell Bourne lo habrámyscript
interpretado el shell Bourne./usr/xpg4/bin/awk 'BEGIN{system("myscript")'
en Solaris 10 lo tendrá interpretado por/usr/xpg4/bin/sh
(lo mismo para/usr/xpg4/bin/env myscript
).find . -prune -exec myscript {} \;
en Solaris 10 (usandoexecvp()
) lo interpretará/bin/sh
incluso con/usr/xpg4/bin/find
, incluso en un entorno POSIX (un error de conformidad).csh -c myscript
lo interpretarácsh
si comienza con#
, de losh
contrario.Con todo, no puede estar seguro de qué shell se usará para interpretar ese script si no sabe cómo y por qué se invocará.
En cualquier caso,
read -p
es unabash
sintaxis única, por lo que querrá asegurarse de que el script sea interpretado porbash
(y evitar esa.sh
extensión engañosa ). O conoce la ruta delbash
ejecutable y usa:O puede intentar confiar en una
$PATH
búsqueda delbash
ejecutable (suponiendo quebash
esté instalado) usando:(se
env
encuentra casi en todas partes/usr/bin
). Alternativamente, puede hacer que sea POSIX + Bourne compatible, en cuyo caso puede usar/bin/sh
. Todos los sistemas tendrán a/bin/sh
. En la mayoría de ellos será (en su mayor parte) compatible con POSIX, pero aún puede encontrar de vez en cuando un shell Bourne allí.fuente
Cuando no tiene ninguna línea
#!
(llamada shebang ), se usa sh . Para verificar eso, puede ejecutar el siguiente script.En mi computadora consigo
incluso si mi shell predeterminado es zsh . Utiliza bash ya que en mi máquina, bash implementa el comando sh .
fuente