MIT 6.1810 Lab Utils xargs Issue: Unexpected Output with find . b | xargs echo

60 Views Asked by At

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);
0

There are 0 best solutions below