由于文件不是系统识别的任何可执行文件类型,并且假设您具有执行该文件的权限,因此execve()
系统调用通常会失败,并显示ENOEXEC
(不是可执行文件)错误。
然后发生什么取决于用于执行命令的应用程序和/或库函数。
例如,可以是一个外壳,即execlp()
/ execvp()
libc函数。
大多数其他应用程序在运行命令时将使用其中任何一个。他们将通过system("command line")
libc函数调用外壳程序,该函数通常将调用sh
该命令行以解析该命令行(可以在编译时确定其路径(例如/bin/sh
vs /usr/xpg4/bin/sh
在Solaris上)),或者$SHELL
像它们自己那样调用存储在其中的shell vi
使用其 !
命令或xterm -e 'command line'
其他命令(su user -c
将调用用户的登录shell而不是$SHELL
)。
通常,不以shebang开头的无Shebang文本文件#
被视为sh
脚本。这sh
是会有所不同,虽然。
execlp()
/ execvp()
,在execve()
返回ENOEXEC
通常会调用sh
就可以了。对于具有多个sh
标准的系统(因为它们可以符合多个标准),sh
通常将在编译时(通过使用execvp()
/ execlp()
通过链接指向的不同路径的不同代码块sh
)确定该标准。例如,在Solaris上,它可以是/usr/xpg4/bin/sh
(标准POSIX sh
),也可以是(/bin/sh
在Solaris 10及更高版本上的Bourne shell(过时的shell),在Solaris 11中是ksh93)。
关于外壳,有很多变化。bash
,AT&T ksh
,Bourne Shell通常会exec
在模拟a之后,自己解释脚本本身(除非使用子进程,否则将在子进程中)execve()
,即未设置所有未导出的变量,关闭所有close-on-exec fds,删除所有自定义陷阱,别名,函数...(bash
将以sh
模式解释脚本)。yash
将执行自身(在模式下sh
也是argv[0]
这样sh
)以对其进行解释。
zsh
,pdksh
,ash
基壳通常将调用sh
(在编译时间,其中所确定的路径)。
对于csh
和tcsh
(以及sh
某些早期BSD的),如果文件的第一个字符是#
,则它们将执行自身以对其进行解释,sh
否则。那可以追溯到shebang之前的一段时间,在那个csh
时候确实可以识别#
为注释,但不能识别为Bourne shell,因此这#
暗示它是一个csh脚本。
fish
(至少是2.4.0版),如果execve()
失败则仅返回错误(它不会尝试将其视为脚本)。
某些shell(例如bash
或AT&T ksh
)将首先尝试试探性地确定文件是否可能是脚本。因此,您可能会发现,如果前几个字节中包含NUL字符,则某些外壳程序将拒绝执行脚本。
另请注意,如果execve()
ENOEXEC失败,但文件确实包含shebang行,则某些shell会尝试自行解释shebang行。
举几个例子:
- 如果
$SHELL
是/bin/bash
,xterm -e 'myscript with args'
将已myscript
被解释bash
的sh
方式。与一起使用时xterm -e myscript with args
,xterm
将使用execvp()
来解释脚本sh
。
su -c myscript
在Solaris 10中,root
登录外壳是Bourne外壳/bin/sh
,/bin/sh
现在是Bourne外壳将由Bourne外壳myscript
解释。
/usr/xpg4/bin/awk 'BEGIN{system("myscript")'
在Solaris 10上,它将由解释/usr/xpg4/bin/sh
(与相同/usr/xpg4/bin/env myscript
)。
find . -prune -exec myscript {} \;
在Solaris 10上(使用execvp()
),即使在POSIX环境中(一致性错误),也将使用/bin/sh
即使使用来解释它/usr/xpg4/bin/find
。
csh -c myscript
csh
如果以开头#
,则以解释,sh
否则为。
总而言之,如果您不知道该脚本的调用方式和调用方式,则无法确定将使用哪个shell来解释该脚本。
在任何情况下,read -p
都是bash
-only语法,因此您需要确保脚本由解释bash
(并避免使用误导性的.sh
扩展名)。您要么知道bash
可执行文件的路径,然后使用:
#! /path/to/bash -
read -p ...
或者您可以尝试通过以下方式依赖于可执行文件的$PATH
查找bash
(假设bash
已安装):
#! /usr/bin/env bash
read -p ...
(env
几乎在中普遍存在/usr/bin
)。或者,可以使它与POSIX + Bourne兼容/bin/sh
。所有系统都有一个/bin/sh
。在大多数情况下,它将(大多数情况下)与POSIX兼容,但是您可能仍然会发现Bourne shell时不时出现。
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"