首页 > 解决方案 > Unix(Mac OS)终端不将 Ctrl+D 视为 EOF

问题描述

我遇到的问题:当我玩getchar()行为时,我发现我的终端(macOS Mohave 版本 10.14.6 18G87)不支持 Ctrl+D 作为 EOF。

我是如何遇到问题的:

下面附上代码getchar(),基本上这个代码是 echo getchar() 如果输入字符不是空白,否则,对于多个连续空白字符,它只输出一个空白字符。代码本身可以工作,但是在终端中运行它时,终端不会将 Ctrl+D 视为 EOF,因此代码永远不会终止。 我确信这是由于我错误地使用了system ("/bin/stty raw");system ("/bin/stty cooked");但是,我不知道如何修复它。

 /* K&R C Exercise 1-9. Write a program to copy its input to its output,
 * replacing each string of one or more blanks by a single blank.*/

#include <stdio.h>
#include <stdlib.h>

int main(void){

    int ch;
    int prev = -1;

    /* if you are in a UNIX like environment
     * the ICANON flag is enabled by default, so input is buffered until the next '\n' or EOF
     * https://stackoverflow.com/a/1799024/5450745
     * */
    system ("/bin/stty raw");

    while ((ch=getchar())!= EOF){
       if (ch != ' ' ){
           if (prev == ' '){
               putchar(prev);
               putchar(ch);
           }
           else{
               putchar(ch);
           }
           prev = ch;
       }
       else{

           prev = ch;
           continue;
       }

    }
    /* use system call to set terminal behaviour to more normal behaviour */
    system ("/bin/stty cooked");

    return 0;
}

我检查了stty,但是,它确实配置EOFCtrl +D. 但是,现在,如果我按Ctrl + D,它只会将终端从一个窗口拆分为两个。

在此处输入图像描述

我可以做些什么来允许EOF重新启用?

谢谢!

标签: cmacosterminalgetcharstty

解决方案


此代码适用于我运行 macOS Catalina 10.15 的 Mac。我希望它在几乎任何你可以使用的类 Unix 系统上都能正常工作,包括旧版本的 macOS。它control-D通过ch'\004'(八进制 4 — 在标准 C 中可写的许多其他方式,包括 just 4)进行比较来发现,在键入并终止循环时被检测到。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int ch;
    int prev = -1;

    /* if you are in a UNIX like environment
     * the ICANON flag is enabled by default, so input is buffered until the next '\n' or EOF
     * https://stackoverflow.com/a/1799024/5450745
     * */
    system("/bin/stty raw");

    while ((ch = getchar()) != EOF && ch != '\004')
    {
        if (ch != ' ')
        {
            if (prev == ' ')
            {
                putchar(prev);
                putchar(ch);
            }
            else
            {
                putchar(ch);
            }
            prev = ch;
        }
        else
        {
            prev = ch;
            continue;
        }
    }
    /* use system call to set terminal behaviour to more normal behaviour */
    system("/bin/stty cooked");

    return 0;
}

当然,输出显示有点奇怪——return例如,键入不会将光标移动到下一行。但是测试ch == '\004'确实检测到何时control-D输入。(空格消除代码也可以。)

使用stty cbreak而不是stty raw使中断启用,但 EOF viacontrol-D仍然被禁用。


推荐阅读