为什么 shebang 需要一条路径?
错误的
#!ruby
正确的
#!/usr/local/bin/ruby
#!/usr/bin/env ruby
操作系统应该具有有关已注册命令的路径的信息,为什么它仍然期望给出它?
答案1
可能是为了让内核更简单。我认为内核不会搜索您的路径来查找可执行文件。这是由 C 库处理的。 #!
处理在内核中完成,不使用标准 C 库。
另外,我认为内核不知道你的路径是什么。 $PATH
是一个环境变量,只有进程才有环境。内核没有。我想它可以访问执行执行的进程的环境,但我认为内核中当前没有任何东西可以访问这样的环境变量。
答案2
您可以PATH
使用 获得搜索语义env
,因此:
#!/usr/bin/env ruby
有你想要的语义
#!ruby
依赖PATH
不被认为是良好实践的原因是脚本无法对 PATH 环境变量的内容做出任何假设,从而破坏了二进制文件的“顺序依赖模型”,其中
/bin
包含启动时所需的可执行文件;/usr/bin
包含操作系统安装使用的其他可执行文件;/usr/local/bin
包含由系统管理员安装的不属于基本操作系统的可执行文件。~/bin
包含用户自己的可执行文件。
每个级别不应假定序列中较晚的二进制文件存在,这些二进制文件更“应用”,但可能依赖于较早的二进制文件,这些二进制文件更“基础”。而PATH变量往往是从应用性走向基础性,这与上面的自然依赖关系是相反的方向。
为了说明这个问题,问问自己,如果 in 中的脚本调用了Ruby~/bin
中的脚本,会发生什么?/usr/local/bin
该脚本应该取决于操作系统安装的版本/usr/bin/ruby
,还是取决于用户碰巧拥有的个人副本~/bin/ruby
? PATH
搜索给出了与后者相关的不可预测的语义(可能~/bin/ruby
是一个损坏的符号链接),而在路径中烘焙#!
给出了前者。
实际上没有任何其他独立于平台的“操作系统......有关注册命令的路径的信息”,因此最简单的事情是坚持#!
.
答案3
我相信这样您就可以根据需要或想要指定一名备用口译员。例如:
#!/home/user/myrubyinterpreter
更常见于 shell 脚本:
#!/bin/bash
#!/bin/sh
#!/bin/dash
#!/bin/csh
答案4
还有其他原因,但从安全角度来看,我永远不希望脚本对正确路径做出假设。如果错误并且运行了错误的 shell 或解释器怎么办?是由恶意用户插入的吗?或者如果它依赖于特定的 shell,并且如果使用错误的 shell 就会崩溃怎么办?
用户可能会弄乱他们的路径并破坏东西 - 不要信任用户:-) 我进行了多次攻击,这些攻击依赖于用户在他们的路径上做错误的事情 - 通常以错误的顺序得到东西 - 所以我可以颠覆正常的脚本调用。
是的,我知道如果您自己编写了脚本,您可以完全正确地声称您已经整理出自己的路径,但解释器无法做出这些决定。