有区别吗,还是只是个人选择?
#!<interpreter> <arguments>
尝试运行 <interpreter> <arguments>
以读取和运行文件的其余部分。
因此,#!/usr/bin/env
表示必须有一个名为 /usr/bin/env
的程序;
#!/bin/env
表示必须有一个名为 /bin/env
的程序。
一些系统具有其中一个而不具有另一个。
根据我的经验,大多数系统都有 /usr/bin/env
,因此 #!/usr/bin/env
更常见。
Unix 系统将尝试使用 execve
运行 <interpreter>
,这就是为什么它必须是完全路径,并且没有路径的 #!env
无法工作的原因。
/
根文件系统在启动时就挂载。/usr
可能会在之后挂载,可能运行来自 /
的脚本和程序以安排挂载。例如:一些站点通过从网络挂载 /usr 来节省空间,但需要先连接到网络。例如:它是一个大型的本地文件系统,但如果它损坏了,你需要像 fsck
这样的工具来尝试修复它。因此,/bin
和 /sbin
(使用 /lib
)必须包含至少一个位于 /bin/sh 的 shell、如 /bin/echo
、/bin/test
等基本脚本,以及诸如 /bin/mount
或 /sbin/mount
、/sbin/fsck
等系统工具......
因此,在不同的 Unix 中,几乎任何程序都可能会:
dash
)作为 /bin/sh 来加快启动速度,但是建立符号链接将 /usr/bin/sh
-> /usr/bin/bash
(如果我没记错,用 "sh" 调用 bash 会将其置于某种 posix 模式下,但它仍然是不同的更强大的 shell)。大多数情况下,只需设置 $PATH 包括两个位置。但是一些上下文环境,如 #!
或 docker exec
需要一个固定的完整路径。因此,使用 env
编写可移植脚本的技巧 - env
恰好执行 PATH 查找。
这些都是有效的用例,但现代 Linux 对 /
本身也遵循了类似的“需要小用户空间来挂载 / 恢复主用户空间”的论点!引入了 pivot 系统调用和 initrd
,并且工具已经成长到可以将你需要的部分复制进去。
现在,/
与 /usr
可以说已经失去了意义。在一个文件系统上同时拥有它们并建立符号链接在原则上对每个人都可行,尽管一些特定的设置会出问题并需要更改......
参见2012年的文章https://lwn.net/Articles/483921/,了解有关“/usr合并”想法的概述。例如Fedora已完成此操作:https://fedoraproject.org/wiki/Features/UsrMove。许多其他发行版还没有这样做,或者仍在讨论中,或正在解决一些问题以减少用户出现问题的概率。例如,请参见Debian的准备工作:https://wiki.debian.org/UsrMerge.
希望使用PATH查找的原因有更多:
env
这样的东西总是存在于/bin或/usr/bin中,或者两者都有,但一个人可能只有(或更喜欢)在/usr/local或家目录下安装python和其他解释器...#!/usr/bin/env python3
的脚本,则这就是您需要使用特定于该环境的模块所需的全部内容。env
本身要使用什么完整路径?按照同样的逻辑,在具有不同/usr的系统中,env
本身可能会缺失其中之一,因此您无法编写100.00%的可移植的#!
命令行。
在实践中,两者都很可能有效。我没有统计数据,但实际上多年来我看到的更常见的形式是/usr/bin/env
(例如示例)。
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"
这是行不通的。
/usr/bin/env
是指向 /bin/env
的软链接。实际上,你正在使用的是 /bin/env
/bin/env
,而/usr/bin/env
是一个符号链接。 - Jared Beck#!
可移植性的所有方面进行了广泛的研究。 - Beni Cherniavsky-Paskin
/bin/bash
,因此建议在那里使用/usr/bin/env
以实现可移植性。另外,如果您想在$PATH
中的不同目录中运行较新版本的BASH,则env
会尊重并使用该目录,而/bin/bash
显然是硬编码的。 - kvz/usr/bin/env
,但没有从/bin/env
到/usr/bin/env
的符号链接。如果你遇到-bash: ./your_command: /bin/env: bad interpreter: No such file or directory
错误,那么就会出现问题。 - Charles Merriam