我在一些脚本语言中注意到了这一点,但是在这个例子中,我使用的是python。在许多教程中,他们会以#!/usr/bin/python3。我不明白我们为什么要这么做。

操作系统不应该知道它是一个python脚本吗(显然它已经安装了,因为你引用了它) 如果用户使用的操作系统不是基于unix的呢 由于某种原因,该语言被安装在不同的文件夹中 用户版本不一致。特别是当它不是完整的版本号时(比如Python3 vs Python32)

如果有的话,我可以看到这破坏了python脚本,因为上面列出的原因。


这条线表示如何。 它被忽略了。 它将无法运行,应该将其更改为指向正确的位置。或者应该使用env。 它将无法运行,并且可能无法在不同的版本下运行。


这叫散列弹。如果从shell运行脚本,它将检查第一行,以确定应该启动哪个程序来解释脚本。

非基于Unix的操作系统将使用自己的规则来确定如何运行脚本。例如,Windows将使用文件名扩展名,而#将导致第一行被视为注释。

如果Python可执行文件的路径是错误的,那么脚本自然会失败。从标准约定指定的任何位置创建到实际可执行文件的链接都很容易。


#!/usr/bin/python3是shebang行。

shebang行定义解释器的位置。在本例中,python3解释器位于/usr/bin/python3shebang行也可以是bash、ruby、perl或任何其他脚本语言的解释器,例如:#!/bin/bash。

如果没有shebang行,操作系统不会知道它是一个python脚本,即使你在脚本上设置了执行标志(chmod +x script.py)并像./script.py那样运行它。要使脚本在python3中默认运行,可以将其作为python3 script.py调用,或者设置shebang行。

你可以使用#!/usr/bin/env python3用于不同系统之间的可移植性,以防语言解释器安装在不同的位置。


这一行帮助找到运行脚本的可执行程序。这种shebang表示法在大多数脚本语言中都是相当标准的(至少在成熟的操作系统中使用)。

这一行的一个重要方面是指定将使用哪个解释器。例如,在许多以开发为中心的Linux发行版上,同时安装几个版本的python是很正常的。

Python 2。x和Python 3不是100%兼容的,所以这个差异是非常重要的。所以# !/usr/bin/python和#!/usr/bin/python3是不一样的(和#!/usr/bin/env python3,如本页其他地方所述。


实际上,决定一个文件是什么类型的文件是非常复杂的,所以现在操作系统不能只知道。它可以根据-进行很多猜测

扩展 泌尿道感染 MIME

但是命令行并没有为此烦恼,因为它运行在一个有限的向后兼容层上,从那时起,那些花哨的废话就没有任何意义了。如果你双击它,现代操作系统当然可以解决这个问题——但如果你从终端运行它,那么就不会,因为终端不会关心你花哨的操作系统特定的文件输入api。

关于其他几点。这很方便,运行起来也很方便

python3路径/ /你/脚本

如果你的python不在指定的路径中,那么它就不能工作,但我们倾向于安装一些东西来让这样的东西工作,而不是相反。是否使用*nix并不重要,它取决于shell是否考虑这一行,因为它是一个shellcode。例如,你可以在Windows下运行bash。

实际上你可以完全省略这一行,这只是意味着调用者必须指定一个解释器。此外,不要将解释器放在非标准位置,然后在不提供解释器的情况下尝试调用脚本。


为了阐明shebang行如何在windows中工作,请参阅3.7 Python文档:

If the first line of a script file starts with #!, it is known as a “shebang” line. Linux and other Unix like operating systems have native support for such lines and they are commonly used on such systems to indicate how a script should be executed. The Python Launcher for Windows allows the same facilities to be used with Python scripts on Windows To allow shebang lines in Python scripts to be portable between Unix and Windows, the launcher supports a number of ‘virtual’ commands to specify which interpreter to use. The supported virtual commands are: /usr/bin/env python The /usr/bin/env form of shebang line has one further special property. Before looking for installed Python interpreters, this form will search the executable PATH for a Python executable. This corresponds to the behaviour of the Unix env program, which performs a PATH search. /usr/bin/python /usr/local/bin/python python


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内核将解析该行的其余部分,并以path /usr/bin/python3和current file作为第一个参数进行另一次exec调用:

/usr/bin/python3 /path/to/script.py

这适用于任何使用#作为注释字符的脚本语言。

类似地,如果你决定使用env,你可能总是应该在python3位于不同位置的系统上工作,特别是pyenv,还可以参阅这个问题,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)。让我们通过读取ELF可执行文件/bin/ls的前4个字节来确认:

head -c 4 "$(which ls)" | hd 

输出:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

因此,当内核看到这些字节时,它会获取ELF文件,将其正确地放入内存中,并使用它启动一个新进程。请参见:内核如何获得在linux下运行的可执行二进制文件?

最后,您可以使用binfmt_misc机制添加自己的shebang处理程序。例如,您可以为.jar文件添加一个自定义处理程序。这种机制甚至支持按文件扩展名的处理程序。另一个应用程序是使用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

这是一种可能性,但这有一个主要的问题,如果我们决定将命令重构为另一种语言,那么一切都会崩溃。

她完美地解决了这个问题。

参见:为什么人们要写#!/usr/bin/env python脚本的第一行?