昨天朋友跟我说我的 MIT6.S081 lab1 的 xargs
命令的代码无法通过,看到他的测试方法才知道原来是这样测试的,感觉之前写的测的都太简略了。
例如测试 xargs
命令这一关可以这样测试:
$ make GRADEFLAGS=xargs grade
之前的博客在这里:MIT6.S081 Lab: Xv6 and Unix Utilities
检查了一下我之前的代码,发现完全没有处理多行的情况,在测试的时候就会出现问题。
偷看一下测试用的脚本:
mkdir a
echo hello > a/b
mkdir c
echo hello > c/b
echo hello > b
find . b | xargs grep hello
所以对于 find . b
,它的结果会是三行:
./a/b
./c/b
./b
管道之后的 xargs 应该执行三次 grep
,这才是正确的行为:
grep hello ./a/b
grep hello ./c/b
grep hello ./b
但是我使用 read()
处理的时候又发现了新的问题,管道不是行缓冲的,不方便直接读入一行,想要换用 scanf()
但是 xv6 没有提供,所以只能一个字符一个字符手动处理:
#include "kernel/types.h"
#include "kernel/param.h"
#include "user/user.h"
int main(int argc, char *argv[]) {
char buf[1024];
char *cmd[MAXARG];
memset(buf, 0, 1024);
memset(cmd, 0, sizeof(char *) * MAXARG);
for (int i = 1; i < argc; ++i) {
cmd[i-1] = argv[i];
}
char ch;
char *p = buf;
int blanked = 1;
int ncmd = argc - 1;
while (read(0, &ch, 1) > 0) {
if (ch == ' ' || ch == '\t') {
*p = '\0';
blanked = 1;
p += 1;
} else if (ch == '\n') {
if (fork() == 0) {
exec(cmd[0], cmd);
} else {
wait(0);
}
memset(buf, 0, sizeof buf);
p = buf;
ncmd = argc - 1;
} else {
if (blanked) {
blanked = 0;
cmd[ncmd] = p;
ncmd += 1;
}
*p = ch;
p += 1;
}
}
exit(0);
}