我正在尝试用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);
现在你的程序应该可以工作了。