I’m working on the MIT 6.1810’s Lab Utils. While testing the xargs functionality using make qemu, I encountered a weird issue.
When I execute the following commands:
echo hello > b
find . b | xargs echo
the output appears as follow:
buf:./b 0
./b
buf:
/b 1
Typically, the output of find . b would be:
./b
However, when I directly run echo ./b (whose output matches find . b), the result of find . b | xargs echo is different from the previous case:
buf:./b
0
./b
Furthermore, if I replace write with printf or fprintf, which normally prints the output to stdout by default or by setting file descriptor argument to 1, respectively. The output of find . b | xargs echo changes signficantly:
buf:. 0
.
buf:/b
0
/b
It appears that during the first pass, the read function reads only the dot ('.'), and during the second pass, it reads the remaining string "/b".
These unexpected outputs have left me puzzled. I wonder why the outputs differ even though the input appears to be the same string, i.e., ./b.
The normal output of the following command should be ./b.
find . b | xargs echo
For my implementation with debug printf, the correct output should be:
buf:./b
0
./b
which is the same as echo ./b | xargs echo.
My implementation for find:
struct dirent de;
struct stat st;
fd = open(path, O_RDONLY);
fstat(fd, &st);
while (read(fd, &de, sizeof(de)) == sizeof(de))
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
stat(buf, &st);
switch (st.type)
{
case T_FILE:
if (strcmp(de.name, name) == 0)
{
write(1, buf, strlen(buf));
write(1, "\n", 1);
//printf("%s\n", buf);
}
break;
...
}
}
Echo’s implementation (supplied by the course):
for (int i = 1; i < argc; i++)
{
write(1, argv[i], strlen(argv[i]);
if (i + 1 < argc)
{
write(1, " ", 1);
}
else
{
write(1, "\n", 1);
}
}
My implementation for xargs:
int _argc = 0;
char *args[MAXARG];
char buf[1024];
char *p;
while (read(0, buf, sizeof(buf)) != 0)
{
printf("buf:%s %d\n", buf, *buf == '\n');
_argc = 0;
for (int i = 1; i < argc; i++)
{
args[_argc++] = argv[i];
}
p = buf;
while (_argc <= MAXARG && *p != '\0')
{
char *tmp = strchr(p, ' ');
if (tmp == 0)
{
tmp = strchr(p, '\n');
if (tmp != 0)
*tmp = '\0';
args[_argc++] = p;
break;
}
*tmp = '\0';
args[_argc++] = p;
p = tmp + 1;
}
if (fork() == 0)
exec(args[0], args);
else
wait(0);
}
exit(0);