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

Gau*_*rma 71 python bash scripts

bashor 中sh,我想任何以 开头的#都是注释

但是在bash脚本中我们写:

#!/bin/bash
Run Code Online (Sandbox Code Playgroud)

在 Python 脚本中,有:

#!/bin/python
Run Code Online (Sandbox Code Playgroud)

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

Eli*_*gan 104

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

你在问shebang线有什么区别和普通注释。

以 开头的行与以#!开头的任何其他行一样都是注释#。如果#!是文件的第一行或其他任何地方,则为真。#!/bin/sh 有效果,但它不会被解释器本身读取

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

假设一个 shell 脚本以#!/bin/sh. 那是一条注释,解释器(shell)会忽略该行之后的所有内容#字符。

#!一行的目的不是向口译员提供信息。该#!行的目的是告诉操作系统(或启动解释器的任何进程)将什么用作解释器

  • 如果您将脚本作为可执行文件调用,例如,通过运行./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 行,并且扩展名可能决定运行脚本的内容。(这并不意味着您需要为您的脚本提供扩展名,但这就是为什么如果您这样做,它们应该是正确的原因之一。)

#!之所以选择服务于这个目的,正是因为 #开始评论。这#!行用于系统,而不是解释器,解释器应该忽略它。

Bash 脚本的 Shebang 行

您(最初)说您#!/bin/sh用于bash脚本。只有在脚本不需要任何bash扩展名时才应该这样做——sh需要能够运行脚本。sh并不总是指向bash. 通常,包括在所有远程最近的 Debian 和 Ubuntu 系统上sh是指向dash.

用于 Python 脚本的 Shebang Line

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

/bin/sh read by the interpretor hello.py
Run Code Online (Sandbox Code Playgroud)

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

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

对于 Python 脚本,如果您知道 Python 解释器在哪里(或将要在哪里),您可以用#!相同的方式编写该行:

#!/usr/bin/python
Run Code Online (Sandbox Code Playgroud)

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

#!/usr/bin/python3
Run Code Online (Sandbox Code Playgroud)

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

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

#!/usr/bin/env python
Run Code Online (Sandbox Code Playgroud)

(或#!/usr/bin/env python3用于 Python 3。)

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

  • env几乎总是位于/usr/bin.
  • 在大多数系统上,python 应该运行您的脚本的是第一个出现在PATH. 开始hello.py#!/usr/bin/env python化妆./hello.py/usr/bin/env python hello.py,这是(几乎)等同于运行python hello.py

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

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

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

其他语言的 Shebang 行

许多编程和脚本语言以及其他一些文件格式都#用作注释。对于它们中的任何一个,该语言中的文件可以由程序运行,该程序通过在#!.

在某些编程语言中,#通常不是注释,但作为特殊情况,如果第一行以#!. 这有助于#!语法的使用,即使#不会以其他方式使一行成为注释。

不作为脚本运行的文件的 Shebang 行

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

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

不作为脚本运行但无论如何都像脚本一样的文件的 Shebang 行

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

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

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

#!/usr/bin/env tee -a
Run Code Online (Sandbox Code Playgroud)

这以交互方式获取用户输入,将其逐行回显给用户,并将其附加到“脚本”文件的末尾。

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

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

  • @gerrit 好问题。在解释器/编译器报告带有行号的消息的任何语言中,注释的 *内容* 被忽略,但注释行仍然 *计数*。在一行代码之前添加注释或空行仍会导致该行代码的行号增加。`-x` "skip[s] the first line..." 第二行被编号为 `1` 而不是 `2`,第三行被编号为 `2` 而不是 `3`,等等。这就是为什么你应该'不要使用那个标志。;) `-x` 用于在非类 Unix 操作系统上编写脚本,这些操作系统具有类似 shebang 的语法而不以 `#` 开头(因此不是 Python 注释)。 (4认同)
  • 在 Perl 中,如果直接启动解释器(`perl script.pl` 与`./script.pl`),那么解释器*将*读取shebang行来解析诸如`-w`之类的标志。但不建议依赖此功能。 (4认同)

Gor*_*vic 7

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

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

#!/bin/sh
Run Code Online (Sandbox Code Playgroud)

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

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

#!/bin/python
Run Code Online (Sandbox Code Playgroud)

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

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

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

来源:此答案的某些部分源自(略有修改)英语维基百科上的Shebang (Unix)(由维基百科贡献者提供)。本文采用CC-BY-SA 3.0 许可,与 AU 上的用户内容相同,因此允许此派生并注明出处。


saj*_*i89 5

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

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

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

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