【问题标题】:What's the difference of using #!/usr/bin/env or #!/bin/env in shebang?在 shebang 中使用 #!/usr/bin/env 或 #!/bin/env 有什么区别?
【发布时间】:2011-07-29 18:35:32
【问题描述】:

会有什么不同还是只是个人选择?

【问题讨论】:

    标签: bash env


    【解决方案1】:

    #!<interpreter> <arguments> 尝试运行 <interpreter> <arguments> 以读取并运行文件的其余部分。

    所以#!/usr/bin/env表示一定有一个叫/usr/bin/env的程序;
    #!/bin/env表示一定有一个叫/bin/env的程序。

    有些系统有一个而没有另一个。

    根据我的经验,大多数都有/usr/bin/env,所以#!/usr/bin/env 更常见。

    Unix 系统会尝试使用execve 运行<interpreter>,这就是为什么它必须是完整路径,而没有路径的#!env 将不起作用。

    【讨论】:

    • 除此之外,非 OSX BSD 没有 /bin/bash,因此建议使用 /usr/bin/env 以实现可移植性。此外,如果你想在 $PATH 中排列的不同目录中运行更新版本的 BASH,env 会尊重并使用它,而 /bin/bash 显然是硬编码的。
    • 特别是,OS/X 有/usr/bin/env 并且没有从/bin/env/usr/bin/env 的符号链接。你会得到一个-bash: ./your_commnd: /bin/env: bad interpreter: No such file or directory 错误。
    【解决方案2】:

    从历史上看,UNIX 有 2 组二进制文件:

    • / 文件系统在启动早期安装。
    • /usr 可能 稍后被挂载,可能运行来自/ 的脚本和程序来安排挂载。示例:某些站点通过从网络挂载 /usr 来节省空间,但您需要先进入网络。示例:它是一个大型本地文件系统,但如果它被损坏,您需要像 fsck 这样的工具来尝试修复它。

    因此,/bin/sbin(使用 /lib)必须包含一个最小系统,包括至少一个位于 /bin/sh 的 shell、脚本必需品,如 /bin/echo/bin/test 等,系统/bin/mount/sbin/mount/sbin/fsck 等工具...

    因此,在不同的 Unix 中,几乎任何程序都可能是:

    • 在 /usr/bin/ 但不在 /bin
    • 在 /bin 但不在 /usr/bin 中
    • 在两者中,与符号链接相同
    • 两者都不同!例如。一些系统使用/bin/sh 是一个非常小的shell(例如dash)以加快启动速度,但符号链接/usr/bin/sh -> /usr/bin/bash(iirc,将bash 调用为“sh”使其进入某种posix 模式,但它是仍然是一个不同的更强大的外壳)。

    大多数时候,只需将 $PATH 设置为包括这两个区域。但是像#!docker exec 这样的一些上下文需要一个固定的完整路径。因此,使用env 编写可移植脚本的技巧——env 恰好进行 PATH 查找。

    发生了什么变化

    这些都是有效的用例,但现代 Linux 也遵循了类似的论点,即 / 本身也需要小用户空间来挂载/恢复主用户空间! The pivot syscall and initrd 被引入,并且工具增长到将您需要的部分复制到其中。

    /usr 统一

    现在,/ vs /usr 可以说失去了它的目的。在一个文件系统上同时使用符号链接对每个人原则上都是可行的,尽管某些特定设置会中断并且必须更改......

    请参阅 2012 年的 https://lwn.net/Articles/483921/ 以了解此“/usr 统一”理念的概述。例如 Fedora 完成了它:https://fedoraproject.org/wiki/Features/UsrMove。许多其他发行版还没有,或者仍在争论它,或者解决一些问题以减少用户。例如看debian的准备:https://wiki.debian.org/UsrMerge

    /usr/local/、~/.local/等地方

    还有更多需要 PATH 查找的理由:

    • 并非所有的 Unix 系统都可以直接安装所有语言,或者它们的软件包太旧了。因此,虽然像 env 这样的东西总是存在于 /bin 或 /usr/bin 或两者中,但可能只有(或更喜欢)python 和其他解释器位于 /usr/local 或您的主目录下......
    • 许多语言版本/库管理器都有在隔离环境中运行的方法,并且经常通过可执行的“垫片”激活此类环境。例如,一个 Python “virtualenv” 目录有一个 bin/python3 二进制文件;因此,当您将该 bin/ 目录添加到您的 PATH 之前,并且如果您运行执行 #!/usr/bin/env python3 的脚本,那么您只需要使用特定于该环境的模块即可。

    回到问题,env 本身使用什么完整路径?

    按照相同的逻辑,在具有不同 /usr 的系统中,env 本身可能会从任一位置丢失,因此您无法编写 100.00% 可移植的 #! 行。
    在实践中,两者都可能起作用。我没有统计数据,但多年来我一直将/usr/bin/env 视为更常用的推荐形式(example)?

    【讨论】:

      【解决方案3】:

      Mikel 的解释很棒,它忽略了一个小事实(这是相当重要的),它只是传递了一个包含所有空格的参数:

      #!<Interpreter> <argument>
      

      调用结果:

      $ <Interpreter> '<argument>' path_to_calling_script
      

      例如:

      $ cat /tmp/test
      #!/usr/bin/env python
      print "hi"
      
      $ /tmp/test
      

      和调用一样:

      $ /usr/bin/env "python" /tmp/test
      

      引号试图表明,如果您添加任何标志或其他值将成为被调用参数的一部分。

       #!/bin/bash -c /bin/env python
      

      将被解释为:

       $ /bin/bash "-c /bin/env python"
      

      这行不通。

      【讨论】:

        【解决方案4】:

        /usr/bin/env 是指向/bin/env 的软链接。本质上,您使用的是/bin/env

        【讨论】:

        • 哪个系统有两个硬文件?
        • Ubuntu 没有 /bin/env。 Solaris 8 将这两个文件分开。
        • @kurumi - 大多数系统根本没有 /bin/env。 /usr/bin/env 在标准位置。
        • Centos 4 有 /bin/env/usr/bin/env 是一个符号链接
        • Fedora 完成 fedoraproject.org/wiki/Features/UsrMove,所以现在 /bin 是符号链接 -> /usr/bin; RHEL/CentOS 紧随其后。许多其他发行版还没有,或者仍在争论它。见wiki.debian.org/UsrMergelwn.net/Articles/483921
        猜你喜欢
        • 2019-05-29
        • 1970-01-01
        • 2011-11-28
        • 1970-01-01
        • 2017-10-03
        • 2014-03-03
        • 1970-01-01
        • 2016-03-23
        • 1970-01-01
        相关资源
        最近更新 更多