实验一 实现带参数的简单 shell
实验一利用课本第 9 页程序 1-5 的框架,实现允许输入命令带参数的简单
shell。原来的实现是不能够带参数的。输入命令所能带的参数个数,只受到系
统键盘输入缓冲区长度(以及 shell 输入缓冲区长度)的限制,该缓冲区的缺省
长度是 4096 个字节。实现时要解决的主要问题有:
1. 正确理解并使用系统调用 fork(),execve()和 waitpid(),特别是 execve()函数。
fork()函数创建一个新的进程。新进程就是所谓的子进程,它是执行 fork()函数
的进程(父进程)的“克隆”,也就是说,子进程执行的程序与父进程的完全一样。
当 fork()函数返回值为 0 时表示处于子进程中;而返回值大于 0 时表示处于父进
程中,此时的返回值是子进程的进程 id。因此,fork()的返回值可以用来划分仅
仅适合父进程和子进程执行的程序段。fork()函数返回值为-1 时表示出错。
如果子进程只是运行与父进程完全一样的程序,那用处是很有限的。要让子进
程运行不同于父进程的程序,就必须调用 execve 函数,它是所有其他 exec 函数
的基础。execve 函数把调用它的进程的程序,替换成 execve 函数的参数所指定
的程序。运行 execve 函数成功后,进程将开始运行新的程序,也就是 execve 函
数的参数所指定的程序。
execve 函 数 原 型 : int execve(const char *path, const char *argv[],const char
*envp[]);
其中:
path:要执行的程序路径名,比如“/bin/ls”,“ cd”,“ /usr/bin/gcc”等等。
argv:参数表,比如 ls 命令中可带的命令行参数-l,-a 等。注意,argv 的第一个
元素必须是要执行的程序(命令)的路径名。
envp:环境变量表,供要执行的命令使用。实参数用 NULL 或系统环境变量
environ 均可。注意,因为 environ 由系统提供,属于外部变量,所以说明时必
须用“extern”修饰。
例子:
char *argv[] = {“gcc”, “-g”, “-c”, “hello.c”, NULL};
char *argv1[] = {“/bin/ls”, “-l”, “-a”, NULL};
execve(“/usr/bin/gcc”, argv, environ); // 编译程序“hello.c”
execve(“/bin/ls”, argv1, NULL); // 执行命令“ls –l –a”
execve(“/usr/ls”, argv1, NULL); // 出错,因为目录/usr/下没有 ls 程序。
// 注意,在 argv1 的第一个字符串“/bin/ls”中,只有 ls 是有用的。
系统调用 waitpid()用于等待子进程结束、获取子进程的运行状态,详细说明在
第八章。本实验仅仅用它使父进程等待子进程结束,因此维持程序 1-5 的用法
即可。
2.根据简单 shell 的输入,构造 execve 函数的参数。
根据程序 1-5,数组 buf 保存用户的输入,包括命令和参数。由于 shell 命令的命
令名和各参数之间是用空格分开,因此可以用空格作为分界符。通过一个循环
可以把 buf 数组中的命令和各个参数依次分离开来,并赋给数组 argv 的各元素
适当的指针值。 argv 数组的最后一个指针必须是 NULL。接着就可以调用