bash如何区分脚本和可执行文件?

时间:2017-10-03 04:41:56

标签: bash unix compilation

我了解到,在脚本语言中,您可以在文件中使用shebang来指示您打算使用的语言和版本。否则,命令./script_name将默认使用bash作为解释器。

为什么bash不尝试使用相同的命令样式./executable来解释编译的程序?换句话说,bash特别指出了什么来区分脚本和可执行文件?

2 个答案:

答案 0 :(得分:1)

答案很复杂。

TLDR

bash没有做任何shebang解释!那不是它的工作。它实际上只是尝试使用正常的exec系统调用来执行程序。唯一的例外是当exec调用返回errno -ENOEXEC时,它会尝试使自己成为解释器。

更长的回答:

  • bash没有!实际上在大多数* nix类似的系统中,甚至在windows中,shell都没有区分shell脚本和#34;和其他类型的可执行文件,并以任何特殊方式处理shell脚本。这留给OS的底层exec引擎。然而,这个一般性陈述有一些警告。我将举例说明Linux,它几乎适用于(至少就用户体验而言)符合POSIX.1标准的系统。

治疗#!在Linux中

在这种情况下,shebang由内核处理。所有shell(例如bash)都会在exec(2)系列调用中执行系统调用,以请求运行程序。

内核本身负责弄清楚如何处理它。它了解一大堆可执行格式,如AOUT,ELF,COFF和是SHEBANG。

相关代码可在fs/binfmt_script.c的Linux内核树中找到,当然也可以在fs/exec.c中找到

static int load_script(struct linux_binprm *bprm)实际执行脚本加载并执行适当的二进制文件。

现在,如果您查看该代码,您会注意到around line 58如果找不到解释器条目,它将返回-ENOEXEC

但是,如果找到解释器条目(并且所有其他条件都可以),则按预期继续执行

那么当没有找到解释器条目时会发生什么?

这意味着脚本在第一行中没有#!,正如内核所期望的那样。

在这种情况下,bash(以及其他交互式shell)继续尝试将自己注入解释器或系统默认shell(例如/ bin / sh)作为解释器。

现在更多bash is doing我建议您使用以下内容创建一个简单的shell脚本 foo

  # Shebang would go here
  # This is foo
  echo "Hello World"


  chmod a+x foo

然后用strace运行foo:

  strace ./foo

然后用strace运行它,但是调用bash并让它运行foo:

  strace /bin/bash -c ./foo

现在注入#!/bin/sh并再次重复这两个步骤。

答案 1 :(得分:1)

可执行文件以magic number开头 - 一个短字节序列,用于标识文件的格式。例如,ELF格式的可执行文件以\x7FELF(十六进制:7f 45 4c 46)等开头.shebang,#!(十六进制:23 21)实际上是一个幻数本身,它将文件标识为一个脚本。这就是为什么shebang 必须正好在文件的开头,而不是(例如)用空格缩进。

当要求系统执行"执行"一个文件,它读取前几个字节并根据它确定要做什么。 bash运行未识别(没有已知的幻数)文件作为bash scrips是一种特殊情况 - 如果系统无法弄清楚如何执行该文件,bash会尝试这样做。