【问题标题】:What does #!/usr/bin/... at the start of a file mean?文件开头的 #!/usr/bin/... 是什么意思?
【发布时间】:2009-07-14 00:04:27
【问题描述】:

我可以在 Haskell 中做这样的事情:

#!/usr/bin/runghc
main=putStrLn "Hello World"

然后我可以用./hello.hs运行它

我的问题是,为什么第一行被忽略了? haskell 中的注释以-- 开头,但第一行似乎仍然被忽略。它甚至加载到 ghci 中。该技巧也适用于 Python 和 Perl。

但是当我在 Java 中做类似的事情时:

#!/usr/local/jdk1.6.0_13/bin/javac
...

Javac 给我一个编译器错误。

那么它是如何工作的,我如何让它与 Java 一起工作?

谢谢。

【问题讨论】:

标签: linux command-line shebang


【解决方案1】:

#!名为“shebang”,是一种 Unix 执行脚本的方式。当您要求操作系统执行一个文件时,它会发现这不是一个普通的 .exe 文件,并且 #!在开始时 用作指示操作系统执行 #! 之后的命令的魔术标记!并连接该命令,使该文件成为该命令的参数

如果 myfile.py 包含

#!/usr/bin/python

执行该文件与运行没有太大区别

$ /usr/bin/python myfile.py

我的 Haskell 知识很差。但是对于您的特定情况,似乎 runghc 命令 只需读取第一行,解析该 #! 上给出的任何参数!行,将文件的其余部分写入一个临时文件并在该临时文件上运行 ghc(这将剥离第一个留置权 - 有关更多信息,请参阅 ghc 源中的 runghc.hs。)

如果你想用 javac 做同样的事情,你可以使用与 runghc 相同的方法。 编写一个包装器,它吃掉文件的第一行,将文件的其余部分写入临时文件并在该文件上运行 javac。

【讨论】:

  • 文本文件没有成为标准输入。原始命令行(可能在文本文件的名称中添加了路径信息)被附加到在 shebang 行上找到的命令中。原始标准输入仍然是扩展命令的标准输入。
  • 免责声明:我对 Java 知之甚少。但是#foo 是 Java 中的注释吗?我知道在 *nix 上的大多数脚本语言中(故意如此),这样您就不必担心剥离第一行。
  • # 在 Java 中不是注释,java 遵循 C/C++ 风格,带有 /**/ 和 // cmets
【解决方案2】:

如果你的文件是hello.hs,并且第一行是“#!/usr/bin/runghc”,那么shell就会执行:

/usr/bin/runghc hello.hs

第一行基本上告诉 shell 用什么来运行脚本。

对于java示例,第一行应该是运行脚本的可执行文件,而不是编译脚本。

【讨论】:

    【解决方案3】:

    我的问题是,为什么第一行被忽略了? haskell 中的注释以 -- 开头,但第一行似乎仍然被忽略。它甚至加载到 ghci 中。该技巧也适用于 Python 和 Perl。

    “技巧”在 Python 和 Perl 中有效,因为 # 在这些语言中开始注释,因此解释器将该行视为注释并忽略它。所以对他们来说,这没什么特别的。

    在 Haskell 中,# 不会开始评论,因此它不会正常工作。但是,GHC(也许还有其他实现,如果有记忆的话,拥抱也是如此)对于 shebang 线有一个特殊情况。如果文件的第一行以#! 开头,则将其视为注释。这种与语言规范的偏差已被完全纳入以使

    $ chmod +x hello.hs
    $ ./hello.hs
    

    工作。它不适用于javac,因为没有内置用于 shebang 行的特殊情况。

    【讨论】:

      【解决方案4】:

      shebang 仅适用于解释性语言....它通常对编译器没有任何意义,在大多数情况下会出错

      【讨论】:

        【解决方案5】:

        之所以可行,是因为 Python、Perl 和 Haskell 显然都是解释型语言。这是指定将运行脚本的解释器的标准 Unix 方式。 Java 是一种编译语言,不能使用解释器运行。

        【讨论】:

          【解决方案6】:

          Javac 是编译器,而不是解释器。

          它缺乏交互模式,我认为这是导致“魔法”的原因。 由于 GCC 缺少相同的功能,因此同样不适用于 GCC。

          例如,dmd(D 编译器)是一个支持 interpertation 的编译器的示例,具有这种交互式编辑(#!/usr/bin/dmd -run)。

          【讨论】:

            【解决方案7】:

            它是您计算机上用于解释您的脚本的可执行文件的位置。 Java 是一种编译语言,因此不需要这样的声明。

            此外,重点是它是一个特殊的注释,Java 中的构造以这种方式是不合法的,因为 # 不是合法的注释标记。如果这样的结构有意义......它没有......它看起来像:

            //!/usr/local/jdk1.6.0_13/bin/javac

            【讨论】:

              【解决方案8】:
              猜你喜欢
              • 2012-02-21
              • 2010-12-02
              • 2013-08-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2022-12-11
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多