为什么不使用无情的shebang?


Answers:


20

PATH查找是用户空间中标准C库的功能,通常环境变量也是如此。内核看不到环境变量,除非它在环境中从调用者传递execve到新进程。

内核不会对路径execve(取决于包装函数,例如execvp执行PATH查找)或在Shebang中(其或多或少在execve内部重新路由调用)的路径进行任何解释。因此,您需要将绝对路径放到shebang¹中。在最初的家当实施只是的几行代码,到现在也没有得到显著因为扩大。

在Unix的第一个版本中,当外壳程序发现您正在调用脚本时,它会自行进行调用。Shebang被添加到内核中有几个原因(总结了Dennis Ritchie基本原理

  • 调用者不必担心要执行的程序是Shell脚本还是本机二进制文件。
  • 脚本本身指定要使用的解释程序,而不是调用程序。
  • 内核在日志中使用脚本名称。

无路径shebang可能需要扩展内核以访问环境变量和进程PATH,或者要求内核执行执行PATH查找的用户空间程序。第一种方法需要给内核增加不成比例的复杂性。第二种方法已经可以通过#!/usr/bin/env射棒实现

¹ 如果放置相对路径,则相对路径将相对于进程的当前目录(而不是包含脚本的目录)进行解释,这在shebang中几乎没有用。


2
不,内核不需要execve在shebang 中也不需要在shebang中使用绝对路径,尽管在shebang中具有相对路径没有多大意义。
斯特凡Chazelas

3
对于任何对“ shebang在内部重新路由execve调用”方式感到好奇的人:它实际上是在需要解释器的可执行文件上运行解释器的通用机制的一部分。动态链接的ELF可执行文件由“解释” /lib64/ld-linux-x86-64.so.2(请参见ldd输出)。Linux使它变得完全通用:binfmt支持(自2.1.43版本开始)使您可以注册解释器路径/ magic-number-or-file-extension对。你可以有PE32 .exe小号调用wine,当你运行它们,Java类和JAR文件调用java,等等,等等
彼得·科德斯

#!/ usr / bin / env -S [shebang]是我运行节点时不知道其路径所必需的(使用nvm-将其放置在与我最初预期的位置不同的位置)。
TamusJRoyce

-S仅从coreutils 8.30开始可用。参见gitlab.com/gnuwget/wget/commit/…
Tim Ruehsen rockdaboot

19

发生的事情比目光所及。#!行由Unix或Linux内核解释,#!不是shell的一个方面。这意味着PATH在内核决定执行什么时,它实际上并不存在。

解决不知道要运行或以perl便携式方式或类似方式调用的可执行文件的最常见方法是使用#!/usr/bin/env perl。内核执行/usr/bin/env,它继承了一个PATH环境变量。env寻找(在这个例子中)perlPATH,并使用execve(2)系统调用来获得内核运行的perl可执行文件。


4
$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0

到完整路径的转换是由外壳程序完成的(更通用:在用户空间中)。内核期望它可以直接访问的文件名/路径。

如果希望系统通过查看PATH变量来找到可执行文件,则可以将shebang重写为#!/usr/bin/env EXEC

但是在这种情况下,搜索也不是内核。


1
转换为完整路径是由外壳程序完成的。谢谢,尽管...该示例是否足以说明问题?如我所见,shell只是在运行strace(转换为/usr/bin/strace某个时刻)时带有2个参数。
Alois Mahdal
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.