我已经注意到了几种脚本语言,但在这个例子中,我使用的是python。在许多教程中,它们将从第一行的#!/usr/bin/python3
开始。我不明白为什么我们有这个。
如果有的话,由于上面列出的原因,我可以看到这打破了python脚本。
答案 0 :(得分:184)
#!/usr/bin/python3
是 shebang line 。
shebang行定义了解释器所在的位置。在这种情况下,python3
解释程序位于/usr/bin/python3
。一个shebang行也可以是bash
,ruby
,perl
或任何其他脚本语言的解释器,例如:#!/bin/bash
。
如果没有shebang行,操作系统就不会知道它是一个python脚本,即使你在脚本上设置执行标志并像./script.py
那样运行它。要使脚本在python3中默认运行,请将其作为python3 script.py
调用或设置shebang行。
如果他们在不同的位置安装了语言解释器,您可以使用#!/usr/bin/env python3
在不同系统中实现可移植性。
答案 1 :(得分:18)
这叫做哈希爆炸。如果从shell运行脚本,它将检查第一行以确定应该启动什么程序来解释脚本。
非基于Unix的操作系统将使用自己的规则来确定如何运行脚本。例如,Windows将使用文件扩展名,#
将导致第一行被视为注释。
如果Python可执行文件的路径错误,那么脚本自然会失败。从标准约定指定的任何位置创建实际可执行文件的链接很容易。
答案 2 :(得分:10)
此行有助于查找将运行脚本的程序可执行文件。这种shebang符号在大多数脚本语言中都是相当标准的(至少在成人操作系统中使用)。
这一行的一个重要方面是指定将使用哪个解释器。例如,在许多以开发为中心的Linux发行版中,同时安装多个版本的python是正常的。
Python 2.x和Python 3不是100%兼容的,因此这种差异非常重要。因此#! /usr/bin/python
和#! /usr/bin/python3
不一样(并且与#! /usr/bin/env python3
完全相同,如本页其他地方所述。
答案 3 :(得分:5)
此行如何。
被忽略。
它将无法运行,应更改为指向正确的位置。或者应该使用env
。
它无法运行,无论如何都无法在不同的版本下运行。
答案 4 :(得分:2)
要弄清shebang行在Windows中的工作原理,请从3.7 Python doc:
答案 5 :(得分:1)
Linux 内核的 exec
系统调用本机理解 shebangs (#!
)
当你使用 bash 时:
./something
在 Linux 上,这将调用 exec
系统调用,路径为 ./something
。
内核的这一行在传递给 exec
的文件上被调用:https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
它读取文件的第一个字节,并将它们与 #!
进行比较。
如果比较结果为真,则该行的其余部分由 Linux 内核解析,这将再次调用 exec
,以路径 /usr/bin/python3
和当前文件作为第一个参数:
/usr/bin/python3 /path/to/script.py
这适用于任何使用 #
作为注释字符的脚本语言。
类似地,如果您决定改用 env
,您可能应该始终这样做,以便在 python3
位于不同位置(特别是 pyenv
)的系统上工作,另请参阅this question,shebang:
#!/usr/bin/env python3
以类似方式结束调用:
/usr/bin/env python3 /path/to/script.py
执行您对 env python3
的期望:在 PATH
中搜索 python3
并运行 /usr/bin/python3 /path/to/script.py
。
是的,您可以使用以下方法进行无限循环:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash 识别出错误:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
恰好是人类可读的,但这不是必需的。
如果文件以不同的字节开始,那么 exec
系统调用将使用不同的处理程序。另一个最重要的内置处理程序是针对 ELF 可执行文件的:https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305,它检查字节 7f 45 4c 46
(对于 .ELF
,它也恰好是人类可读的)。让我们通过读取 /bin/ls
的前 4 个字节来确认,这是一个 ELF 可执行文件:
head -c 4 "$(which ls)" | hd
输出:
00000000 7f 45 4c 46 |.ELF|
00000004
因此,当内核看到这些字节时,它会获取 ELF 文件,将其正确放入内存中,并使用它启动一个新进程。另见:How does kernel get an executable binary file running under linux?
最后,您可以使用 binfmt_misc
机制添加您自己的 shebang 处理程序。例如,您可以添加 custom handler for .jar
files。这种机制甚至支持文件扩展名的处理程序。另一个应用是transparently run executables of a different architecture with QEMU。
我不认为 POSIX 指定了 shebangs 但是: https://unix.stackexchange.com/a/346214/32558 ,尽管它确实在基本原理部分中提到,并且以“如果系统支持可执行脚本,可能会发生某些事情”的形式出现。不过 macOS 和 FreeBSD 似乎也实现了它。
PATH
搜索动机
很可能,shebangs 存在的一大动机是在 Linux 中,我们经常希望从 PATH
运行命令,就像:
basename-of-command
代替:
/full/path/to/basename-of-command
但是,如果没有 shebang 机制,Linux 怎么知道如何启动每种类型的文件?
在命令中硬编码扩展:
basename-of-command.py
或在每个解释器上实现 PATH 搜索:
python3 basename-of-command
有可能,但这有一个主要问题,如果我们决定将命令重构为另一种语言,一切都会中断。
Shebangs 很好地解决了这个问题。
另见:Why do people write #!/usr/bin/env python on the first line of a Python script?
答案 6 :(得分:0)
实际上,确定文件的文件类型非常复杂,因此现在操作系统不能仅仅知道。它可以根据-
做出很多猜测但是命令行并不打扰所有这一切,因为它在有限的向后兼容层上运行,从那一刻开始,废话毫无意义。如果您双击确定,现代操作系统可以解决这一问题,但是如果您从终端运行它,则不会,因为终端并不关心您的操作系统特定的文件键入API。
关于其他要点。这很方便,也可以运行
python3 path/to/your/script
如果您的python不在指定的路径中,则它将不起作用,但是我们倾向于安装一些东西来使诸如此类的东西起作用,而不是相反。您是否在* nix下实际上并不重要,因为这是shellcode
,所以是否要考虑此行取决于您的外壳。因此,例如,您可以在Windows下运行bash
。
实际上您可以完全省略此行,这仅意味着调用方将必须指定解释器。另外,请勿将您的口译员放在非标准位置,然后尝试在不提供口译员的情况下调用脚本。