【问题标题】:Issue with CTRL+D on Windows Subsystem for LinuxLinux 的 Windows 子系统上的 CTRL+D 问题
【发布时间】:2019-07-23 19:30:07
【问题描述】:

我正在使用适用于 Linux 的 Windows 子系统进行作业。下面是用于为此作业编写迷你 shell 的 C 代码。 我在使用 WSL 时遇到了一个有趣的问题。在第 35 行,您可以看到我调用了 read 函数来读取缓冲区并检查是否为空。当按下 Ctrl+D 时,在使用 WSL 时,它将进入 if 语句并在第 36 行无限打印打印消息,直到我使用 才停止Ctrl+C 退出。当在 Linux 机器上运行这个程序时,它的行为适当并打印一次,并将我们带到循环的顶部。
关于这个错误可能是什么的任何想法?

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

char prompt[] = "$ ";

static int
Fork()
{
  pid_t pid;

  if ((pid = fork()) < 0)
    error(EXIT_FAILURE, errno, "fork error");
    return(pid);
}

int    
main(void)
{
  long MAX = sysconf(_SC_LINE_MAX);
  char buf[MAX];
  pid_t pid;
  int status, n;

  do {
    write(STDOUT_FILENO, prompt, strlen(prompt));
    fflush(NULL);
    memset(buf, 0, MAX);
    if((n = read(STDIN_FILENO, buf, MAX)) == 0) {
      printf("use exit to exit shell\n");
      continue;
    }
    buf[strlen(buf) - 1] = '\0'; // chomp '\n'

    if (strncmp(buf, "exit", MAX) == 0) { // match
      break;
    }
    pid = Fork();
    if (pid == 0) {  // child
      execlp(buf, buf, (char *)NULL);
      error(EXIT_FAILURE, errno, "exec failure");
    }
    // parent
    if ((pid = waitpid(pid, &status, 0)) < 0)
      error(EXIT_FAILURE, errno, "waitpid error");
  } while(1);
  exit(EXIT_SUCCESS);
}

程序是用 C 语言编写的,但没有可用于插入 C 代码 sn-ps 的选项。

【问题讨论】:

  • 您的程序试图读取文件结尾。我觉得这不是一个好主意。显然 Windows 同意并在以下读取时继续返回文件结尾。
  • OT: about: buf[strlen(buf) - 1] = '\0'; // chomp '\n' 这不是删除尾随换行符的可靠方法。更好的方法是:buf[ strcspn( buf, "\n" ) ] = '\0';
  • OT: about: static int Fork() {` 将函数命名为与 C 库函数相同的名称是一种非常糟糕的编程习惯(即使大小写不完全相同。)这可以让人类读者非常困惑
  • 您可能期望被 ctrl/D 中断的 read() 返回 -1 而不是 0。这似乎是与系统相关的行为。我有一个真正的 Ubuntu,它也返回 0。即使 read() 会返回 -1,下面的代码也是可疑的。如果 strlen(buf) == 0 怎么办?那么buf[strlen(buf) -1] 会做什么呢?
  • @eryksun 我给你的标准规范链接说“如果设置了 ICANON,处理时应丢弃 EOF 字符。”。如果 WSL 未能做到这一点,则必须使用 TCIFLUSH 手动丢弃 EOF 字符。使用TCSET* 来回更改 tty 模式也可能会导致这种副作用。但这些都不是必需的(在任何 Unix 系统上都不是必需的)。

标签: c windows windows-subsystem-for-linux


【解决方案1】:

有关 read() 的文档(Linux 手册页 v 3.54)没有指定文件结尾 (ctrl/D) 导致 read 返回 0 以外的任何值。相反,它说返回值零表示文件结尾。所以你依赖于未定义的行为。 不知何故,你的 Linux ctrl/D 会导致错误,因此 read() 返回 -1。在这种情况下,您的程序将退出循环。或者,按字面意思读取 ctrl/D,然后 read() 返回 1。

【讨论】:

    【解决方案2】:

    不同的操作系统对 EOF 使用不同的击键。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-14
      • 2020-08-19
      • 2021-11-20
      • 2021-05-05
      相关资源
      最近更新 更多