Gre*_*Cat 17 linux bash shell freebsd dash-shell
当一个类似Bash的脚本作为没有shebang的二进制文件执行时,如何以及由谁决定执行什么?
我想用 shebang 运行一个普通的脚本是用binfmt_script Linux模块处理的,它检查一个shebang,parses命令行并运行指定的脚本解释器.
但是当有人在没有shebang的情况下运行脚本时会发生什么?我已经测试了直接execv方法并发现那里没有内核魔法 - 即像这样的文件:
$ cat target-script
echo Hello
echo "bash: $BASH_VERSION"
echo "zsh: $ZSH_VERSION"
Run Code Online (Sandbox Code Playgroud)
运行仅执行execv调用的已编译C程序会产生:
$ cat test-runner.c
void main() {
if (execv("./target-script", 0) == -1)
perror();
}
$ ./test-runner
./target-script: Exec format error
但是,如果我从另一个shell脚本执行相同的操作,它将使用与原始shell脚本相同的shell解释器运行目标脚本:
$ cat test-runner.bash #!/bin/bash ./target-script $ ./test-runner.bash Hello bash: 4.1.0(1)-release zsh:
如果我使用其他shell执行相同的技巧(例如,Debian的默认值sh- /bin/dash),它也可以:
$ cat test-runner.dash #!/bin/dash ./target-script $ ./test-runner.dash Hello bash: zsh:
神秘的是,它与zsh没有达到预期的效果,并且不遵循一般方案./bin/sh毕竟看起来像zsh 在这些文件上执行:
greycat@burrow-debian ~/z/test-runner $ cat test-runner.zsh #!/bin/zsh echo ZSH_VERSION=$ZSH_VERSION ./target-script greycat@burrow-debian ~/z/test-runner $ ./test-runner.zsh ZSH_VERSION=4.3.10 Hello bash: zsh:
请注意,ZSH_VERSION在父脚本工作,而ZSH_VERSION在孩子没有!
如果没有shebang,shell(Bash,破折号)如何确定执行的内容?我试图在Bash/dash来源中挖掘那个地方,但是,唉,看起来我有点迷失在那里.任何人都可以了解决定在没有shebang的目标文件是作为脚本执行还是作为Bash/dash中的二进制执行的魔法?或者可能存在的某种内核/ libc的互动,然后我会欢迎它是如何在Linux和FreeBSD内核/ libcs工作的解释?
Sor*_*gal 16
由于这种情况发生在破折号和破折号更简单,我先看了一下.
看起来像exec.c是一个值得关注的地方,而且相关的函数tryexec就是调用shellexec它,只要shell需要执行命令就会调用它.而且(简化版)tryexec函数如下:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,它只是总是替换命令以执行自身的路径(_PATH_BSHELL默认为"/bin/sh"),如果ENOEXEC发生.这里真的没有魔力.
我发现FreeBSD bash在其自身中表现出相同的行为sh.
bash处理这个的方式类似但更复杂.如果你想进一步研究它,我建议你阅读bash ,然后execute_command.c专门看一下.评论非常具有描述性.execute_shell_scriptshell_execve
(看起来Sorpigal已经覆盖了它,但我已经输入了它,它可能是有意义的.)
根据Unix FAQ的3.16节,shell首先查看幻数(文件的前两个字节).一些数字表示二进制可执行文件 #!表示该行的其余部分应解释为shebang.否则,shell会尝试将其作为shell脚本运行.
此外,似乎csh查看第一个字节,如果是#,它将尝试将其作为csh脚本运行.
| 归档时间: |
|
| 查看次数: |
4069 次 |
| 最近记录: |