26

我有一个简单的 perl 脚本,如下所示:

#!/usr/bin/perl

use strict;
use warnings;

print "hello world!\n";

我可以按如下方式执行此脚本:

>temp.pl
hello world!
>

如果我添加一些这样的评论:

#this script is just for test
#the shebang
#!/usr/bin/perl

use strict;
use warnings;

print "hello world!\n";

当我尝试执行时,它给我的输出如下:

> temp.pl
use: Command not found.
use: Command not found.
print: Command not found.
> 

这里的重点是,无论如何,shebang 线都应该始终位于顶部。谁能解释为什么?

4

4 回答 4

39

shebang 必须是第一行,因为它是由内核解释的,它查看可执行文件开头的两个字节。如果这些是#!该行的其余部分,则将其解释为要运行的可执行文件以及该程序可用的脚本文件。(细节略有不同,但这就是图片)。

由于内核只会查看前两个字符并且没​​有其他行的概念,因此您必须将 hash bang 放在第 1 行。

现在如果内核无法执行以 开头的文件会发生什么#!whatever?shell 试图派生一个可执行文件并被内核告知它不能执行该程序,作为最后的手段,它试图将文件内容解释为一个 shell 脚本。由于 shell 不是 perl,你会得到一堆错误,就像你试图运行一样

 sh temp.pl
于 2012-10-16T09:32:32.903 回答
8

不仅仅是它必须是第一行,字符#!还必须是文件中的前两个字节。这可以运行脚本是一种外壳功能,而不是操作系统功能,并且它不特定于任何特定的脚本语言。

当系统被告知执行文件的内容时,无论是使用类似的东西.../path/to/bin/program,还是通过 PATH 的类似路径,它都会检查文件的前几个字节以寻找揭示文件类型的“幻数”它是(您可以使用 file(1) 命令查看该过程)。如果它是一个已编译的二进制文件,那么它将以适当的方式加载并执行它,如果前两个字节是#!它,它将执行“shebang-hack”。

'shebang-hack' 是一些 shell 使用的一种特殊情况(实际上,基本上是每个 shell,但它是约定而不是要求),其中 shell 读取剩余的字节到换行符,将这些解释为文件名,然后执行该文件,将当前文件的其余部分作为输入。加上一些你可能在别处读到的细节。

有些(版本的)shell 将允许很长的第一行,有些只允许短的;有些允许多个参数,有些只允许一个。

如果文件不是以 开头#!,但确实是文本,则某些 shell 将试探性地尝试执行它。Csh(如果我没记错的话)认为它是一个 csh 脚本,如果第一行是空白的,那么对于一些 shell 的行为来说,存在一些复杂而神秘的情况,因为生命太短而无法记住。

Sven Mascheck 的 #! 页

于 2012-10-16T09:31:08.383 回答
8

除了上面的解释,这里这里这里都有详细介绍,还有一些关于 Perl 的特殊事情#!还没有提到。

Perl 读取该#!行并做两件事。首先,如果路径看起来不像 perl,它将使用它重新执行程序!例如...

#!/bin/sh

echo "Hello world!"

如果执行为 . 将正确运行perl /path/to/that/program。我不知道 Perl 这样做的历史原因是什么,但是当您使用 Test::Harness 测试多种语言时,它会派上用场。

第二件事是 Perl 找到#!行中的任何开关并应用它们,就像它们在命令行上一样。这就是为什么#!/usr/bin/perl -w要打开警告的原因。

值得一提的是,与 shebang 处理的其他部分不同,这一切都是在 Perl 内部完成的,而不是 Unix,因此可以移植到 Windows。

另一个 Perl + shebang 注释是您可能在许多 Perl 程序的顶部发现的这种疯狂。

#!/usr/bin/perl

eval 'exec /usr/bin/perl -w -S $0 ${1+"$@"}'
    if 0; # not running under some shell

有时,在非常、非常、非常古老的系统上,#!无法运行,Perl 程序由 shell 执行。eval强制外壳首先使用 Perl 重新执行文件。由于 shell 语句以换行符结束,因此看不到if 0. Perl 确实看到了if 0,所以它不执行 eval。Perl 和 shell 都有语法上等效eval的运算符,这使得 hack 工作。

于 2012-10-16T09:52:47.270 回答
0

至少在 POSIX 兼容系统上,shebang 用于告诉可执行加载器如何处理设置了可执行位的文本文件。

加载器知道如何处理二进制文件,它们以“幻数”开头,这些天通常与 ELF 相关。

另一方面,没有 shebang 的文本文件由机器上可用的 POSIX 兼容 shell 执行,这就是为什么你有这些 shell 错误消息:

use: Command not found.
use: Command not found.
print: Command not found.

当你的可执行文件不被 POSIX 兼容的 shell 解释时,你需要告诉加载器使用什么解释器。其他操作系统(如 Windows)选择文件扩展名来解决这个问题,但 Unix 在这种特定情况下不使用或关心扩展名。它使用的是第一行的shebang,它说明了要使用的命令解释器。唯一的缺点是脚本语言应该忽略第一行。希望这是#大多数脚本语言的注释行前缀的情况。

尽管普遍认为,可移植脚本根本不应该有shebang。特别#!/bin/sh不建议他们使用。

于 2012-10-16T10:44:20.843 回答