Como o arquivo não é de nenhum dos tipos de executável reconhecido pelo sistema e supondo que você tenha permissão para executar esse arquivo, a chamada do sistema execve()
normalmente falhará com ENOEXEC
( não um executável ).
O que acontece, então, é com a função de aplicativo e / ou biblioteca usada para executar o comando.
Isso pode ser, por exemplo, um shell, a função execlp()
/ execvp()
libc.
A maioria dos outros aplicativos usará um desses quando executar um comando. Eles invocarão um shell, por exemplo, pela função system("command line")
libc, que normalmente chamará sh
para analisar essa linha de comando (o caminho pode ser determinado em tempo de compilação (como /bin/sh
vs /usr/xpg4/bin/sh
no Solaris). )), ou invoca o shell armazenado em $SHELL
por si só como vi
com seu comando !
, ou xterm -e 'command line'
e muitos outros comandos ( su user -c
invocará o shell de login do usuário em vez de $SHELL
).
Geralmente, um arquivo de texto sem texto que não comece com #
é considerado como um script sh
. Qual sh
é variando.
execlp()
/ execvp()
, sobre execve()
retornando ENOEXEC
normalmente invocará sh
sobre ele. Para sistemas que têm mais de um sh
, porque podem estar em conformidade com mais de um padrão, que sh
normalmente será determinado no tempo de compilação (do aplicativo usando execvp()
/ execlp()
vinculando um blob diferente de código que se refere a um caminho diferente para sh
). Por exemplo, no Solaris, isso será /usr/xpg4/bin/sh
(um padrão, POSIX sh
) ou /bin/sh
(o shell Bourne (um shell antiquado) no Solaris 10 e mais antigo, ksh93 no Solaris 11).
Quando se trata de projéteis, há muita variação. bash
, AT & T ksh
, o shell Bourne normalmente interpretará o script em si (em um processo filho, a menos que exec
seja usado) depois de ter simulado um execve()
, ou seja, todas as variáveis não exportadas foram fechadas. os fds close-on-exec, removeram todos os traps customizados, aliases, funções ... ( bash
interpretará o script no modo sh
). yash
será executado em si mesmo (com sh
como argv[0]
so no modo sh
) para interpretá-lo.
Os shells com base em
zsh
,
pdksh
,
ash
normalmente chamarão
sh
(o caminho do qual determinado no tempo de compilação).
Para csh
e tcsh
(e o sh
de alguns BSDs iniciais), se o primeiro caractere do arquivo for #
, eles serão executados para interpretá-lo e sh
caso contrário. Isso remonta a um tempo pré-shebang em que csh
reconheceu #
como comentários, mas não o shell Bourne, então o #
foi uma dica de que era um script csh.
fish
(pelo menos versão 2.4.0), apenas retorna um erro se execve()
falhar (ele não tenta tratá-lo como um script).
Alguns shells (como bash
ou AT & T ksh
) primeiro tentam determinar heuristicamente se o arquivo provavelmente é um script ou não. Então você pode achar que alguns shells se recusarão a executar um script se ele tiver um caractere NUL nos primeiros bytes.
Observe também que se execve()
falhar com ENOEXEC, mas o arquivo tiver uma linha shebang, alguns shells tentam interpretar eles mesmos a linha shebang.
Então, alguns exemplos:
- Quando
$SHELL
for /bin/bash
, xterm -e 'myscript with args'
terá myscript
interpretado por bash
em sh
mode. Enquanto com xterm -e myscript with args
, xterm
usará execvp()
, então o script será interpretado por sh
.
-
su -c myscript
no Solaris 10, onde o shell de login de root
é /bin/sh
e /bin/sh
é que o shell Bourne terá myscript
interpretado pelo shell Bourne.
-
/usr/xpg4/bin/awk 'BEGIN{system("myscript")'
no Solaris 10 fará com que seja interpretado por /usr/xpg4/bin/sh
(o mesmo para /usr/xpg4/bin/env myscript
).
-
find . -prune -exec myscript {} \;
no Solaris 10 (usando execvp()
) fará com que seja interpretado por /bin/sh
mesmo com /usr/xpg4/bin/find
, mesmo em um ambiente POSIX (um bug de conformidade).
-
csh -c myscript
terá interpretado por csh
se começar com #
, com sh
caso contrário.
No geral, você não pode ter certeza de qual shell será usado para interpretar esse script se você não souber como e por que ele será invocado.
Em todo caso, a sintaxe read -p
é bash
-only, portanto, convém garantir que o script seja interpretado por bash
(e evitar essa extensão .sh
enganosa). Você conhece o caminho do executável bash
e usa:
#! /path/to/bash -
read -p ...
Ou você pode confiar em uma consulta $PATH
do executável bash
(assumindo que bash
está instalado) usando:
#! /usr/bin/env bash
read -p ...
( env
é quase encontrado em /usr/bin
). Alternativamente, você pode torná-lo compatível com POSIX + Bourne, caso em que você pode usar /bin/sh
. Todos os sistemas terão um /bin/sh
. Na maioria deles será (na maior parte) compatível com POSIX, mas você ainda pode encontrar de vez em quando um Bourne shell.
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"