【问题标题】:fgets loops many times before exiting for EOFfgets 在退出 EOF 之前多次循环
【发布时间】:2012-09-23 11:06:54
【问题描述】:

我正在制作一个简单的外壳。它还需要能够逐行读取文本文件。这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>

// Exit when called, with messages
void my_exit() {
    printf("Bye!\n");
    exit(0);
}

int main(void) {

  setvbuf(stdout, NULL, _IONBF, 0);

  // Char array to store the input
  char buff[1024];

  // For the fork
  int fid;

  // Get all the environment variables
  char dir[50];
  getcwd(dir,50);
  char *user = getenv("USER");
  char *host = getenv("HOST");

  // Issue the prompt here.
  printf("%s@%s:%s> ", user, host, dir);

  // If not EOF, then do stuff!
  while (fgets(buff, 1024, stdin) != NULL) {

    // Get rid of the new line character at the end
    // We will need more of these for special slash cases
    int i = strlen(buff) - 1;
    if (buff[i] == '\n') {
      buff[i] = 0;
    }

    // If the text says 'exit', then exit
    if (!strcmp(buff,"exit")) {
      my_exit();
    }

    // Start forking!
    fid = fork();

    // If fid == 0, then we have the child!
    if (fid == 0) {

      // To keep track of the number of arguments in the buff
      int nargs = 0;

      // This is a messy function we'll have to change. For now,
      // it just counts the number of spaces in the buff and adds
      // one. So (ls -a -l) = 3. AKA 2 spaces + 1. Really in the
      // end, we should be counting the number of chunks in between
      // the spaces.
      for (int i = 0; buff[i] != '\0'; i++) {
        if (buff[i] == ' ') nargs ++;
      }

      // Allocate the space for an array of pointers to args the
      // size of the number of args, plus one for the NULL pointer.
      char **args = malloc((sizeof(char*)*(nargs + 2)));

      // Set the last element to NULL
      args[nargs+1] = NULL;

      // Split string into tokens by space
      char *temp = strtok (buff," ");

      // Copy each token into the array of args
      for (int i = 0; temp != NULL; i++) {
        args[i] = malloc (strlen(temp) + 1);
        strcpy(args[i], temp);
        temp = strtok (NULL, " ");
      }

      // Run the arguments with execvp
      if (execvp(args[0], args)) {
        my_exit();
      }
    }

    //  If fid !=0 then we still have the parent... Need to
    //  add specific errors.
    else {
        wait(NULL);
    }

    // Issue the prompt again.
    printf("%s@%s:%s> ", user, host, dir);
  }

  // If fgets == NULL, then exit!
  my_exit();
  return 0;
}

当我将它作为 shell 单独运行时,它运行良好。当我运行 ./myshell

commands.txt 是:

ls -l -a
pwd
ls

但是输出是:

>Bye!
>Bye!
>Bye!
>Bye!
>Bye!
>Bye!>Bye!
>Bye!
>Bye!
>Bye!

甚至不运行我的命令。有任何想法吗?我认为我的 while 循环非常简单。

【问题讨论】:

  • 尝试在 my_exit() 中打印进程的 PID,看看谁在打印什么。
  • 您至少需要在打印提示后刷新输出,以便它出现在相对于命令输出的正确位置。
  • 打印出 PID,除了最后一个 19147 之外,我得到所有 0(每个 Bye!)
  • 一些与您的问题无关的cmets。如果您不使用argcargv,只需声明int main(void)。对 userhost 的分配进行强制转换是多余的,分配可能是初始化:char *user = getenv("USER"); char *host = getenv("HOST");
  • 请不要破坏您的问题。在你得到一些答案或 cmets 之前,改变事情是可以的;即使您有一些 cmets,也可以进行更改。然而,一旦你开始得到答案,你就必须更加小心地做出改变。对于那些通过删除他们回答时可见的 90% 代码来帮助您完全使他们的回答无效的人来说,这是不公平的。

标签: c while-loop fgets


【解决方案1】:

我不知道这是否是 问题,但您(正确地)在评论中提到您必须在 *args 数组中分配“为 NULL 指针加一个”。

但是,您实际上并没有将 *args 中的最后一个指针设置为 NULL。

execvp() 不喜欢这样。

这并不能解释为什么重定向输入与非重定向输入之间可能存在差异,除了未定义的行为是混蛋。

【讨论】:

  • 谢谢 - 我已将最后一个指针设置为 NULL,但奇怪的行为仍在发生
【解决方案2】:

对不起大家 - 原来我的文本文件是来自 Mac 的 TextEdit GUI 的某种疯狂格式。一切都很好。

我非常感谢所有有用的回复

【讨论】:

  • 您能否详细说明一下这种形式的痴呆症,以及痴呆症是如何表现出来的?
  • 当然!我保存了 TextEdit 文件,但它是 .rtf - 所以我只是将其重命名为 .txt ...这导致文件顶部出现奇怪的字符(关于 RTF 格式),然后是命令。因此,当程序以 .txt 输入运行时,它试图执行完全奇怪的命令。我通过尝试 cat commands.txt 发现了这一点...我首先使用 TextEdit 的原因是因为我一直在通过我的 Mac @ home SSH 连接到我的 Unix 服务器。我想创建一个文本文件进行测试,所以我在 TextEdit 中创建了它,并使用 Cyber​​Duck 对其进行了 SCP。
猜你喜欢
  • 2012-11-06
  • 2012-09-14
  • 2018-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多