我们知道, 如果在linux的shell中执行ls, 那么实际上shell对应的进程是父进程, ls对应的进程是子进程。 我们已经模拟过ls了, 下面, 我们来模拟一下shell, 让我们模拟的shell来执行linux的ls, pwd等命令, 模拟linux shell程序如下(也就是说, 下面程序就相当于一个shell):
#include <stdio.h>
#include <sys/wait.h>
#define MAX_LINE 10000
int main()
{
int pid = 0;
int status = 0;
int len = 0;
char buf[MAX_LINE] = {0};
printf("\n$$$");
while(fgets(buf, MAX_LINE, stdin) != NULL)
{
len = strlen(buf) - 1;
if ('\n' == buf[len]) // 去掉尾部的换行符号
{
buf[len] = '\0';
}
pid = fork(); // fork一个子进程出来, 这个子进程主要用于拉起新的其他进程(比如ls进程, pwd进程等)
if (pid < 0)
{
printf("error1\n");
return 1;
}
if (0 == pid)
{
// 子进程调用execlp来执行新的程序, 实际上就是拉起新的进程, 且最后一个参数必须为空指针
execlp(buf, buf, (char *)0);
printf("error2\n"); // 如果用户输入的是abc这样不存在的命令, 则会走到这里
return 1;
}
if (waitpid(pid, &status,0) < 0) // 父进程阻塞地等待子进程执行完毕
{
printf("error3\n");
return 1;
}
printf("\n$$$");
}
return 0;
}
结果如下:
[taoge@localhost learn_c]$ ls
a.out test.c
[taoge@localhost learn_c]$ ./a.out
$$$ls
a.out test.c
$$$pwd
/home/taoge/Desktop/learn_c
$$$abc
error2
$$$ls
a.out test.c
$$$
a.out test.c
[taoge@localhost learn_c]$ ./a.out
$$$ls
a.out test.c
$$$pwd
/home/taoge/Desktop/learn_c
$$$abc
error2
$$$ls
a.out test.c
$$$
可以看到, 我们自己写的shell通过fork来创建一个子进程, 然后这个子进程又拉起了一个新的ls进程, 而这个子进程和ls对应进程的进程号是相同的。
实际上是linux自己shell进程拉起了我们自己写的shell进程, 然后我们的shell进程又拉起了ls进程。