编写一个简单的 UNIX xargs 程序,从标准输入中读取行并为每一行运行一个命令,将该行作为命令的参数提供。你的解决方案应该放在 user/xargs.c 中。 - 使用
fork() 和 exec() 在每一行输入上调用命令。在 parent 中使用 wait() 等待 child 完成命令。 - 要读取单个输入行,请一次读取一个字符,直到出现换行符(
'\n' )。 kernel/param.h 声明了 MAXARG ,如果你需要声明一个 argv 数组,这可能很有用。- 将程序添加到
Makefile 的 UPROGS 中。 - 文件系统的变化在
qemu 的运行中持续存在。使用 make clean 然后再 make qemu 让一个干净的文件系统运行。
- 根据提示,我们需要调用
fork() 创建子进程,和调用 exec() 执行命令。我们知道要从标准输入中读取行并为每行运行一个命令,且将该行作为命令的参数。即把输入的字符放到命令后面,然后调用 exec() 。我们可以依次处理每行,根据空格符和换行符分割参数,调用子进程执行命令。 - 首先,我们定义一个字符数组,作为子进程的参数列表,其大小设置为
kernel/param.h 中定义的 MAXARG ,用于存放子进程要执行的参数。而后,建立一个索引便于后面追加参数,并循环拷贝一份命令行参数,即拷贝 xargs 后面跟的参数。创建缓冲区,用于存放从管道读出的数据。 - 然后,循环读取管道中的数据,放入缓冲区,建立一个新的临时缓冲区存放追加的参数。把临时缓冲区追加到子进程参数列表后面。并循环获取缓冲区字符,当该字符不是换行符时,直接给临时缓冲区;否则创建一个子进程,把执行的命令和参数列表传入
exec() 函数中,执行命令。当然,这里一定要注意,父进程一定得等待子进程执行完毕。
// Lab Xv6 and Unix utilities // xargs.c
#include "kernel/types.h" #include "kernel/stat.h" #include "user/user.h" #include "kernel/param.h"
#define MAXN 1024
int main(int argc, char *argv[]) { // 如果参数个数小于 2 if (argc < 2) { // 打印参数错误提示 fprintf(2, "usage: xargs command\n"); // 异常退出 exit(1); } // 存放子进程 exec 的参数 char * argvs[MAXARG]; // 索引 int index = 0; // 略去 xargs ,用来保存命令行参数 for (int i = 1; i < argc; ++i) { argvs[index++] = argv[i]; } // 缓冲区存放从管道读出的数据 char buf[MAXN] = {"\0"}; int n; // 0 代表的是管道的 0,也就是从管道循环读取数据 while((n = read(0, buf, MAXN)) > 0 ) { // 临时缓冲区存放追加的参数 char temp[MAXN] = {"\0"}; // xargs 命令的参数后面再追加参数 argvs[index] = temp; // 内循环获取追加的参数并创建子进程执行命令 for(int i = 0; i < strlen(buf); ++i) { // 读取单个输入行,当遇到换行符时,创建子线程 if(buf[i] == '\n') { // 创建子线程执行命令 if (fork() == 0) { exec(argv[1], argvs); } // 等待子线程执行完毕 wait(0); } else { // 否则,读取管道的输出作为输入 temp[i] = buf[i]; } } } // 正常退出 exit(0); }
在 Makefile 文件中, UPROGS 项追加一行 $U/_xargs\ 。编译并运行 xv6 进行测试。 $ make clean ... $ make qemu ... init: starting sh $ echo hello too | xargs echo bye bye hello too
退出 xv6 ,运行单元测试检查结果是否正确。 ./grade-lab-util xargs
通过测试样例。 make: 'kernel/kernel' is up to date. == Test xargs == xargs: OK (1.8s)
你不赞👍,我不赞👍,up推文没人看
你关注👇,我关注👇,下次再来不迷路
|