所以,我以为我对此有很好的了解,但是只是进行了一次测试(回应我不同意某人的谈话),发现我的理解是有缺陷的...
尽可能详细地说明我在Shell中执行文件时会发生什么情况?我的意思是,如果我键入以下内容:如果./somefile some arguments
在外壳程序中键入内容,然后按return键(并且somefile
存在于cwd中,并且我具有的读取和执行权限somefile
),那么在幕后会发生什么?
我以为答案是:
exec
,将路径传递给somefile
somefile
并查看文件的幻数,以确定它是否是处理器可以处理的格式somefile
被读取/映射到内存。创建了一个堆栈,执行跳转到的代码的入口点somefile
,并ARGV
初始化为参数数组(a char**
,["some","arguments"]
)exec()
如上所述产生一个新进程,但是所使用的可执行文件是shebang引用的解释器(例如/bin/bash
或/bin/perl
),somefile
并传递给STDIN
但是有人告诉我,如果文件是纯文本,那么Shell会尝试执行命令(就像我键入一样bash somefile
)。我不相信这一点,但我只是尝试了一下,这是正确的。因此,我显然对这里实际发生的事情有一些误解,并且想了解其机制。
当我在shell中执行文件时,会发生什么情况?(尽可能多的细节是合理的...)
关于Linux上“程序如何运行”的最终答案是LWN.net上的两篇文章,令人惊讶的是,程序如何运行以及程序如何运行:ELF二进制文件。第一篇文章简要介绍了脚本。(严格来说,最终答案在源代码中,但是这些文章更易于阅读,并提供了源代码的链接。)
一个小小的实验表明,您几乎完全正确,并且包含shell的简单命令列表文件的执行需要由shell处理。所述的execve(2)手册页包含用于测试程序的源代码,的execve; 我们将用它来查看没有外壳的情况。首先,编写一个testscr1
包含以下内容的测试脚本:
#!/bin/sh
pstree
另一个testscr2
,仅包含
pstree
使它们都可执行,并验证它们是否都从外壳运行:
chmod u+x testscr[12]
./testscr1 | less
./testscr2 | less
现在,使用execve
(假设您在当前目录中构建了它)再试一次:
./execve ./testscr1
./execve ./testscr2
testscr1
仍然运行,但testscr2
产生
execve: Exec format error
这表明外壳的处理方式testscr2
不同。尽管它不处理脚本本身,但仍然可以/bin/sh
用来执行脚本。这可以通过管道来验证testscr2
到less
:
./testscr2 | less -ppstree
在我的系统上,我得到
|-gnome-terminal--+-4*[zsh]
| |-zsh-+-less
| | `-sh---pstree
如您所见,有一个我正在使用的外壳程序zsh
,它启动了less
,还有另一个外壳程序sh
(dash
在我的系统上)简单地运行脚本,该脚本程序运行了pstree
。在in中zsh
由zexecve
in处理Src/exec.c
:shell用于execve(2)
尝试运行命令,如果失败,它将读取文件以查看其是否具有shebang,并进行相应的处理(内核也将完成此操作),以及失败,它尝试使用来运行文件sh
,只要它没有从文件中读取任何零字节即可:
for (t0 = 0; t0 != ct; t0++)
if (!execvebuf[t0])
break;
if (t0 == ct) {
argv[-1] = "sh";
winch_unblock();
execve("/bin/sh", argv - 1, newenvp);
}
bash
具有相同的行为,execute_cmd.c
并通过有用的注释实现(如taliezin所指出的):
执行一个简单的命令,希望该命令在磁盘文件中的某个位置定义。
fork ()
- 连接管道
- 查找命令
- 进行重定向
execve ()
- 如果
execve
失败,请查看文件是否设置了可执行模式。如果是这样,并且它不是目录,则将其内容作为Shell脚本执行。
POSIX定义一组功能,被称为的exec(3)
功能,它包裹execve(2)
并提供此功能太; 有关详细信息,请参见muru的答案。在Linux上,至少这些功能是由C库而不是内核实现的。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句