如何在c中向stdin发送换行符并允许fgets(cmdline、MAXLINE、stdin)接收它



我目前正在c中构建一个shell程序。我被要求使用信号来捕捉CTRL-C信号,并输出"使用出口",要求用户使用我内置的命令出口离开myshell。我已经添加了信号处理程序来输出"Use exit",但无法使我的shell在"Use exit"之后输出[/]>。

预期结果:

[assignment2] > ^C
Use exit
[assignment2] > ^C
Use exit
[assignment2] > ^C
Use exit
[assignment2] > exit

然而,我的程序的输出在每次^C使用退出后都没有[assignment2]>输出,我必须在键盘上按enter键才能显示[assignment 2]>:

[assignment2] > ^C
Use exit
^C
Use exit
^C
Use exit
[assignment2] > exit

我怀疑在处理完信号后,程序仍然停留在fgets(cmdline、MAXLINE、stdin(中,因此程序不会继续到while循环的开头以打印出[assignment2]>,如我的代码中所示:

我的myshell和handle信号函数代码:

// Signal handler funciton
void handler(int signal){
switch(signal) {
case SIGINT:
write(STDOUT_FILENO, "nUse exitn", 10);
break;
case SIGTSTP:
write(STDOUT_FILENO, "nUse exitn", 10);
break;
case SIGQUIT:
write(STDOUT_FILENO, "nUse exitn", 10);
break;
}
int main(){
// Add signal handler
if (signal(SIGINT, handler) == SIG_ERR) {
perror("signal");
} else if (signal(SIGTSTP, handler) == SIG_ERR){
perror("signal");
} else if (signal(SIGQUIT, handler) == SIG_ERR){
perror("signal");
}
// ...... init cmdline and cwd char
while(1){
char dir[MAXPATH];
getcwd(cwd, sizeof(cwd));
printf("[%s] > ", parsecwd(cwd));
if (get_cmd_line(cmdline) == -1) // The program is stuck inside this funciton
continue; /* empty line handling */
eval(cmdline); /* Evaluate and process the cmd input*/
}
}

int get_cmd_line(char *cmdline)
{
int i;
int n;
if (!fgets(cmdline, MAXLINE, stdin))  // The program is stuck in this fgets
return -1;
// Ignore the newline character
n = strlen(cmdline);
cmdline[--n] = '';
i = 0;
while (i < n && cmdline[i] == ' ') {
++i;
}
if (i == n) {
// Empty command
return -1;
}
return 0;
}

我已经尝试向信号处理程序添加一个write(STDIN_FILENO,"\n",1(,以尝试将新行传递给fgets(cmdline,MAXLINE,STDIN(,这样它就会返回-1以继续while循环的开始:

switch(signal) {
case SIGINT:
write(STDOUT_FILENO, "nUse exitn", 10);
write(STDIN_FILENO, "n", 1);
break;
case SIGTSTP:
write(STDOUT_FILENO, "nUse exitn", 10);
write(STDIN_FILENO, "n", 1)
break;
....

但这并不能解决问题,它只是在终端中打印出一条新的线路。

知道如何解决这个问题吗?非常感谢。

signal的标准库(glibc(实现使用BSD语义,这意味着当信号发生时,系统调用将"重新启动"(而不是失败(。

这种行为使得例如fgets在信号处理程序完成时不返回。

要控制此行为,请改用推荐的sigaction函数。更具体地说,确保未设置SA_RESTART标志:

struct sigaction action = { 0 };  // Initialize all members to zero or null
action.sa_handler = &handler;
sigaction(SIGINT, &action, NULL);

这样,fgets函数将返回一个NULL指针,并且errno应该等于EINTR

最新更新