像在原始外壳中一样处理 Ctrl + C



我正在尝试用C实现小型shell程序,该程序将从stdin读取命令,解析它们并执行。我遇到了像在原始外壳中一样处理 Ctrl+C 的问题 - 当您键入几个字母或不键入任何内容,然后按 Cntrl + C 时,shell 只会返回新的提示:

user@user-pc:/$ some letters^C
user@user-pc:/$ 

下面是一个简化的代码来展示我这样做的方法:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
char        interruption;
void        read_line(char **str)
{
    char    c;
    int     size;
    int     i;
    c = 0;
    size = 30;
    i = -1;
    *str = (char*)malloc(sizeof(char) * size + 1);
    while (c != 'n' && !interruption)
    {
        i++;
        if (i == size)
            *str = realloc((void*)*str, (size_t)((size *= 2) + 1));
        read(0, &c, 1);
        (*str)[i] = c;
    }
    if (interruption)
    {
        free(*str);
        *str = NULL;
        interruption = 0;
    }
    else
        (*str)[i] = '';
}
void        handler(int sig_num)
{
    (void)sig_num;
    signal(SIGINT, handler);
    interruption = 1;
    printf("ninterruption happenedn");
}
int         main()
{
    char    *str;
    signal(SIGINT, handler);
    interruption = 0;
    while (1)
    {
        str = NULL;
        write(1, "%> ", 3);
        read_line(&str);
        if (str)
            printf("parsing %sn", str);
        else
            printf("skipping...n");
    }
    return (0);
}

我的方法中的问题是按 Ctrl+C 提示符后不会返回,因为 read(( 只有在我按 Enter 时才开始实际读取输入。这是我的学校作业,除了 read(( 之外,我不能使用任何函数从 stdin(( 中读取字符。

在这种情况下,重现 shell 行为的正确方法是什么?

首先...永远不要在信号处理程序中使用printf或任何其他不能保证异步信号安全的函数。

真。只是不要。

其次,使用sigaction函数而不是signal函数来安装信号处理程序,就像那样。所以这是信号处理程序的代码:

void handler(int sig_num) {
    (void)sig_num;
    interruption = 1;
}

下面是安装处理程序的代码:

struct sigaction action = { 0 }; /* if your compiler frowns at it use {{ 0 }} */
action.sa_handler = handler;
sigaction(SIGINT, &action, NULL);

现在你的程序应该可以工作了。

最新更新