【发布时间】: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