当类似Bash的脚本以二进制形式执行而没有shebang时,如何确定由谁执行?
我猜想 使用 shebang 运行普通脚本是由binfmt_script Linux模块处理的,该模块检查shebang,解析命令行并运行指定的脚本解释器。
但是,如果有人在没有脚本的情况下运行脚本会发生什么?我已经测试了直接execv方法,发现里面没有内核魔术,即像这样的文件:
execv
$ cat target-script echo Hello echo "bash: $BASH_VERSION" echo "zsh: $ZSH_VERSION"
运行仅执行execv调用的已编译C程序将产生:
$ cat test-runner.c void main(){ 如果(execv(“ ./ target-script”,0)== -1) perror(); } $ ./测试运行器 ./target-script:执行格式错误
但是,如果我从另一个shell脚本执行相同的操作,它将使用与原始脚本相同的shell解释器运行目标脚本:
$ cat test-runner.bash #!/ bin / bash ./target-script $ ./test-runner.bash 你好 bash:4.1.0(1)-发布 zsh:
如果我对其他外壳(例如,Debian的默认设置sh- /bin/dash)执行相同的操作,那么它也可以工作:
sh
/bin/dash
$ cat test-runner.dash #!/ bin /破折号 ./target-script $ ./test-runner.dash 你好 重击: zsh:
奇怪的是,它与zsh的配合使用效果不佳,也没有遵循一般的方案。看起来zsh /bin/sh毕竟对这样的文件执行了:
/bin/sh
greycat @ burrow-debian〜/ z / test-runner $ cat test-runner.zsh #!/ bin / zsh 回声ZSH_VERSION = $ ZSH_VERSION ./target-script greycat @ burrow-debian〜/ z / test-runner $ ./test-runner.zsh ZSH_VERSION = 4.3.10 你好 重击: zsh:
请注意,ZSH_VERSION在父脚本中有效,而ZSH_VERSION在子脚本中则无效!
ZSH_VERSION
如果没有shebang,shell(Bash,破折号)如何确定执行什么操作?我试图在Bash / dash来源中挖掘该位置,但是,a,我似乎迷失了。任何人都可以阐明一种神奇的方法,这种方法确定应将没有shebang的目标文件作为脚本执行还是作为Bash / dash中的二进制文件执行?或者可能存在 的 某种互动的内核/ libc和那么我会在它是如何在Linux和FreeBSD内核/ libcs工作欢迎解释吗?
由于这种情况发生在破折号中,并且破折号比较简单,因此我首先看了一下。
看起来像exec.c是查找的地方,而相关的函数是tryexec,shellexec只要需要执行shell指令,就会从中调用。tryexec函数(的简化版本)如下:
tryexec
shellexec
STATIC void tryexec(char *cmd, char **argv, char **envp) { char *const path_bshell = _PATH_BSHELL; repeat: execve(cmd, argv, envp); if (cmd != path_bshell && errno == ENOEXEC) { *argv-- = cmd; *argv = cmd = path_bshell; goto repeat; } }
因此,如果发生的话,它总是简单地用其自身的路径替换要执行的命令(_PATH_BSHELL默认为"/bin/sh")ENOEXEC。这里真的没有魔术。
_PATH_BSHELL
"/bin/sh"
ENOEXEC
我发现FreeBSD bash本身就表现出相同的行为sh。
bash
的方式bash处理这个问题是类似的,但要复杂得多。如果您想进一步研究它,我建议您阅读bash的内容,然后execute_command.c专门阅读execute_shell_script然后shell_execve。这些评论具有描述性。
execute_command.c
execute_shell_script
shell_execve