解释器是否读取了#!/ bin / sh?

bashsh ,我猜任何以#开头的都是评论

但是在bash脚本中我们写道:

 #!/bin/bash 

在Python脚本中,有:

 #!/bin/python 

这是否意味着#本身就是一个评论,而#! 不是?

#! 在脚本运行之前使用line,然后在脚本运行忽略。

你问的是shebang系列和普通评论之间有什么区别。

一行以#!开头#!#开头的任何其他行一样多。 这是真的,如果#! 是文件的第一行,或其他任何地方。 #!/bin/sh 有效 ,但解释器本身无法读取

#不是所有编程语言中的注释,但是,正如您所知,它是Bourne样式shell中的注释,包括shbash (以及大多数非Bourne样式的shell,如csh )。 它也是Python中的评论 。 它是各种配置文件中的注释,根本不是脚本(如/etc/fstab )。

假设shell脚本以#!/bin/sh开头。 这是一个注释,解释器(shell)忽略#字符后面的所有内容。

#!的目的#! line不是为解释器提供信息。 #!的目的#! line是告诉操作系统(或任何进程启动解释器) 使用什么作为解释器

  • 如果您将脚本作为可执行文件调用,例如,通过运行./script.sh ,系统将查询第一行以查看是否以#!开头#! ,后跟零个或多个空格,后跟一个命令。 如果是,则运行该命令,并将脚本名称作为其参数。 在此示例中,它运行/bin/sh script.sh (或技术上, /bin/sh ./script.sh )。

  • 如果通过显式调用解释器来调用脚本,那么#! 从来没有咨询过这条线。 所以,如果你运行sh script.sh ,第一行没有效果。 如果script2.sh的第一行是#!/usr/games/nibbles ,运行sh script2.sh将不会尝试在nibbles打开脚本(但是./script2.sh会)。

您会注意到,在任何情况下,脚本的扩展名( .sh )(如果有的话)都会影响它的运行方式。 在类Unix系统中,这通常不会影响脚本的运行方式。 在其他一些系统上,比如Windows, #! shebang line可能被系统完全忽略,扩展可能决定运行脚本的是什么。 (这并不意味着您需要提供脚本扩展,但这是其中一个原因,如果您这样做,它们应该是正确的。)

#! 被选中的目的恰恰是因为 #开始发表评论。 #! line是系统而不是解释器,解释器应该忽略它。

Shebang Line for Bash Scripts

你(最初)说你使用#!/bin/sh作为bash脚本。 只有在脚本不需要任何bash的扩展时才应该这样做 – sh需要能够运行脚本。 sh并不总是bash的符号链接。 通常,包括所有最近的Debian和Ubuntu系统, sh是一个dash的符号链接。

Shebang Line for Python Scripts

你还说(在你的问题的第一个版本中,在编辑之前)你用#!/bin/sh read by the interpretor启动你的Python脚本。 如果你的意思是字面意思,那么你绝对应该停止这样做。 如果hello.py以该行开头,则运行./hello.py执行:

 /bin/sh read by the interpretor hello.py 

/bin/sh将尝试执行一个名为read的脚本( by the interpretor hello.py作为其参数), read将(希望)找不到,并且Python解释器永远不会看到您的Python脚本。

如果你犯了这个错误但没有我正在描述的问题,你可能通过显式指定解释器(例如, python hello.py )来调用你的Python python hello.py ,导致第一行被忽略。 当您将脚本分发给其他人,或者很久以后使用它们时,可能并不清楚这对他们来说是必要的。 现在最好修复它们。 或者至少完全删除第一行,这样当它们无法以./运行时,错误消息./意义。

对于Python脚本,如果您知道Python解释器的位置(或将要是),您可以编写#! 以同样的方式排队:

 #!/usr/bin/python 

或者,如果它是Python 3脚本,则应指定python3 ,因为python几乎总是Python 2 :

 #!/usr/bin/python3 

但问题是,虽然/bin/sh应该始终存在,并且/bin/bash几乎总是存在于操作系统附带bash的系统上,但Python可能存在于各种各样的地方。

因此,许多Python程序员使用它代替:

 #!/usr/bin/env python 

(或者Python 3的#!/usr/bin/env python3 。)

这使得脚本依赖于env处于“正确的位置”而不是依赖于python在正确的位置。 这是件好事,因为:

  • env几乎总是位于/usr/bin
  • 在大多数系统上,无论运行哪个python脚本都是首先出现在PATH中的脚本。 使用#!/usr/bin/env python启动hello.py ./hello.py运行/usr/bin/env python hello.py ,这实际上等同于运行python hello.py

你不能使用#!python的原因是:

  • 您希望指定的解释器由绝对路径给出(即以/开头)。
  • 调用进程将在当前目录中执行python 。 当命令不包含斜杠时搜索路径的行为是特定的shell行为。

偶尔Python或其他不是shell脚本的脚本会有一个以#!/bin/sh ...开头的shebang行#!/bin/sh ...其中...是其他一些代码。 这有时是正确的,因为有一些方法可以使用参数调用Bourne兼容shell( sh )以使其调用Python解释器。 (其中一个参数可能包含python 。)但是,对于大多数用途, #!/usr/bin/env python更简单,更优雅,更有可能以您想要的方式工作。

Shebang Lines in Other Languages

许多编程和脚本语言以及一些其他文件格式使用#作为注释。 对于它们中的任何一个,语言中的文件可以由程序运行,该程序通过在#!之后的第一行指定程序将其作为参数#!

在某些编程语言中, #通常不是注释,但作为特殊情况,第一行如果以#!开头则被忽略#! 。 这便于使用#! 语法,即使#不会使一行成为评论。

Shebang为不运行脚本的文件行

虽然它不太直观,但任何文件格式都可以容纳以#!开头的第一行的文件#! 其次是可执行文件的完整路径可以有一个shebang行。 如果你这样做,并且文件被标记为可执行文件,那么你可以像程序一样运行它……使它像文档一样打开。

某些应用程序故意使用此行为。 例如,在VMware中, .vmx文件定义虚拟机。 您可以“运行”虚拟机,就像它是一个脚本一样,因为这些文件被标记为可执行文件,并且有一个shebang行,导致它们在VMware实用程序中打开。

Shebang为那些不像脚本运行但是像脚本一样的文件

rm删除文件。 它不是脚本语言。 但是,可以运行启动#!/bin/rm并标记为可执行文件的文件,当您运行它时,会在其上调用rm ,将其删除。

这通常被概念化为“文件删除自身”。 但该文件根本没有运行。 这更像是上面描述的.vmx文件的情况。

不过,因为#! line有助于运行简单命令(包括命令行参数),您可以通过这种方式执行某些脚本。 作为比#!/bin/rm更复杂的“脚本”的简单示例,请考虑:

 #!/usr/bin/env tee -a 

这会以交互方式接收用户输入,逐行回复用户,并将其附加到“脚本”文件的末尾。

有用? 不是特别的。 概念上有趣吗? 完全! 是。 (有些。)

概念上类似的编程/脚本概念(只是为了好玩)

  • 例如, 一次使用多种语言的脚本/程序, 以模拟没有它的操作系统中的hashbangfunction 。

    (这些程序被称为polyglots ,但这不能与软件开发中的其他多语言感混淆, 软件开发是一个程序/项目,其中不同的部分用不同的语言编写。)

  • QBasic / QuickBASIC中的元命令,用于代码生成的编译器(用于编译代码)选项,但是是注释的一部分,因此在实际编译/解释期间被忽略。

一个shebang是字符序列,由字符编号和感叹号(例如“#!”)组成,当它作为脚本初始行的最初两个字符出现时。

在* nix操作系统下,当运行以shebang开头的脚本时,程序加载器将脚本初始行的其余部分解析为解释器指令; 而是运行指定的解释器程序,将其作为参数传递给尝试运行脚本时最初使用的路径。 例如,如果脚本以路径“path / to / your-script”命名,并且它以以下行开头:

 #!/bin/sh 

然后指示程序加载程序运行程序“/ bin / sh”,例如Bourne shell或兼容的shell,将“path / to / your-script”作为第一个参数传递。

因此,脚本以路径“path / to / python-script”命名,并从以下行开始:

 #!/bin/python 

然后加载的程序被指示运行程序“/ bin / python”而不是Python解释器,将“path / to / python-script”作为第一个参数传递。

简而言之,“#”会在字符序列“#!”时注释掉一行。 作为脚本初始行的前两个字符出现的含义如上所述。

有关详细信息,请参阅为什么某些脚本以#开头! ……?

来源:这个答案的某些部分来自英语维基百科上的Shebang(Unix) (由维基百科贡献者提供 )。 本文根据CC-BY-SA 3.0获得许可 ,与AU上的用户内容相同,因此允许使用归属进行推导。

#! 当它作为脚本初始行上的最初两个字符出现时被称为shebang 。 它在脚本中用于指示要执行的解释器。 shebang用于操作系统(内核),而不是shell; 所以它不会被解释为评论。

礼貌: http //en.wikipedia.org/wiki/Shebang_%28Unix%29

一般来说,如果一个文件是可执行的,但实际上不是一个可执行(二进制)程序,并且这样的一行存在,那么#!之后指定的程序! 以scriptname及其所有参数启动。 这两个字符#和! 必须是文件中的前两个字节!

详细信息: http //wiki.bash-hackers.org/scripting/basics#the_shebang

不,它仅由Linux内核的exec系统调用使用,并被解释器视为注释

当你在bash上做:

 ./something 

在Linux上,它使用路径./something调用exec系统调用。

在传递给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/env python和当前文件作为第一个参数进行另一个exec调用:

 /usr/bin/env python /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文件,将其正确放入内存,然后使用它启动新进程。 另见: https : //stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861

最后,您可以使用binfmt_misc机制添加自己的shebang处理程序。 例如,您可以为.jar文件添加自定义处理程序 。 此机制甚至通过文件扩展名支持处理程序。 另一个应用程序是使用QEMU透明地运行不同体系结构的可执行文件 。

我不认为POSIX指定shebangs: https ://unix.stackexchange.com/a/346214/32558,虽然它确实提到了基本原理部分,并且forms为“如果系统支持可执行脚本可能发生”。