为什么 LD_PRELOAD 对没有 shebang 的脚本不生效?

Why doesn't LD_PRELOAD take effect with scripts having no shebang?

如果,当我 运行 脚本时,我使用 LD_PRELOAD 指定要预加载的库,我发现实际上仅当脚本有 shebang 行时才预加载该库。例如,给定这个脚本:

# Not a shebang
echo Hello

和这个命令:

LD_PRELOAD=/path/to/preload_me.so ./script.sh

脚本 运行 根本没有加载库,我可以通过其初始化代码的(非)效果来监控它。

另一方面,如果我添加一个 shebang 行:

#!/bin/sh
echo Hello

... 然后库 当我通过相同的命令 运行 脚本时加载。指定哪个解释器似乎并不重要。当然,我也可以使用 /bin/bash 或我尝试过的任何其他 sh-family shell。

为什么会有差异,有什么方法可以确保在给定的 shell 简单命令之前预加载给定的库,而不管命令是什么?

(改编自 another question,其作者拒绝用这些术语表达问题。)

(改编自我对引用的其他问题的回答。)

必须了解 LD_PRELOAD 变量对操作系统或 shell 没有特殊意义。它只有在与动态链接器结合使用时才具有意义和效果——如果它有的话。如果未使用动态链接器,则 LD_PRELOAD 只是环境中的另一个变量。同样,如果动态链接器无法识别该变量(例如 OS X)。

同样重要的是要理解,当执行名称对应于非可执行格式但包含 shebang 行的文件的命令时,指定的解释器将被执行,即使它是 shell 本身。如果解释器是一个 ELF 二进制文件,它会使用动态链接器。另一方面,如果没有 shebang 行,则 bash 在 subshell 环境中执行文件的内容,这不需要使用动态链接器;相反,shell 只是分叉。其他 shell 可能会也可能不会这样做。

认识到存在 ELF 以外的可执行格式也很重要。在基于现代 ELF 的系统上,您不太可能 运行 进入这样的二进制文件,但您不应该排除这种可能性。

底线:无法确保在通过 bash 或另一个 shell 由用户选择。如果您需要为任何或每个任意命令预加载这样的库,那么您需要更严格地控​​制执行环境,可能通过提供自定义 shell 和自定义动态链接器,并防止任何其他人正在使用。