为什么shebang线总是第一线呢?

时间:2012-10-16 08:44:51

标签: perl unix solaris shebang

我有一个简单的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 个答案:

答案 0 :(得分:27)

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

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

如果内核无法执行以#!whatever开头的文件,会发生什么? shell试图将可执行文件分叉并由内核通知它无法执行程序,作为最后的手段尝试将文件内容解释为shell脚本。由于shell不是perl,因此会出现一堆错误,与尝试运行

时完全相同
 sh < temp.pl

答案 1 :(得分:7)

除了上面详细介绍herehere以及here的解释之外,还有一些关于#!和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

有时,在非常非常非常旧的系统上,#!不起作用,并且shell执行Perl程序。 eval强制shell首先使用Perl重新执行该文件。由于shell语句以换行符结尾,因此它看不到if 0。 Perl确实看到if 0,所以它不执行eval。 Perl和shell都有语法上等效的eval运算符,这使得黑客工作。

答案 2 :(得分:6)

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

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

'shebang-hack'是一个特殊情况,被一些shell使用(事实上,基本上每一个,但它是约定而不是一个要求),其中shell读取剩余的字节直到换行,解释这些作为文件名,然后执行该文件,将其余的当前文件作为输入。您还可以阅读一些关于elsewhere的详细信息。

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

如果文件不是以#!开头,但看起来似乎是文本,那么一些shell会启发式尝试执行它。 Csh(如果我没记错的话)对它是一个csh脚本,并且如果第一行是空白的,生命太短暂而无法记住的话,有一些复杂而神秘的案例与一些shell的行为有关。

Sven Mascheck's #! page处有一些有趣且广泛的细节(以及与我的回忆相符的准确细节!)。

答案 3 :(得分:0)

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

加载器知道如何处理二进制文件,它们以&#34;幻数&#34;开头,通常与ELF有关。

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

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

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

尽管人们普遍认为,便携式脚本根本不应该有一个shebang。特别是{。1}}不建议使用它们。