将命令导入shell后,shell中的C无限循环

将命令导入shell后,shell中的C无限循环,c,shell,infinite-loop,C,Shell,Infinite Loop,我目前正在尝试为一个类构建一个自定义shell。我能够毫无问题地执行从这个shell发出的命令,但是如果我将我的命令管道化到shell中,我将得到一个无限循环。我不知道为什么会发生这种情况。下面的示例将导致无限循环 echo "ls" | ./myshell 当然,如果命令中出现管道,我必须重定向程序的输出,例如ls | grep test。在我的外壳内,这是完美的。我正在使用fork(),execv(),当然还有pipe+dup在子进程之间重定向流 似乎fgets()无法从上次发出的命令中清

我目前正在尝试为一个类构建一个自定义shell。我能够毫无问题地执行从这个shell发出的命令,但是如果我将我的命令管道化到shell中,我将得到一个无限循环。我不知道为什么会发生这种情况。下面的示例将导致无限循环

echo "ls" | ./myshell
当然,如果命令中出现管道,我必须重定向程序的输出,例如
ls | grep test
。在我的外壳内,这是完美的。我正在使用
fork()
execv()
,当然还有
pipe
+
dup
在子进程之间重定向流

似乎
fgets()
无法从上次发出的命令中清除
STDIN\u FILENO

对于命令
echo“ls”|./myshell
我的程序将执行以下操作:(最简单的工作示例)

编辑:最小工作示例

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

int running = 1;
int exit_code = 0;

char cwd[256];
char command[256];
char args[10][256];
char buffer[256] __attribute__((aligned(4096)));

void handle_command(char* buffer, int buffer_size)
{
  int c = 0;
  int argsCount = -1;
  int lastIndex = 0;

  for (c = 0; c < buffer_size && buffer[c]; c++)
  {
    if (argsCount > 10)
    {
      argsCount = 10;
      printf("Argument Count is limited to 10 (no dynamic memory allocation) all other arguments will be ignored\n");
      break;
    }
    if (buffer[c] == '\r' || buffer[c] == '\n' || buffer[c] == ' ')
    {
      if (argsCount == -1)
      {
        memcpy(command, buffer + lastIndex, c - lastIndex);
        command[c - lastIndex] = 0;
      }
      else
      {
        memcpy(args[argsCount], buffer + lastIndex, c - lastIndex);
        args[argsCount][c - lastIndex] = 0;
      }
      argsCount++;
      lastIndex = c + 1;

    }
  }

  if (strcmp(command, "exit") == 0)
  {
    c = 4;
    while (buffer[c] == ' ')
      c++;
    exit_code = atoi(&buffer[c]);
    printf("Exiting Shell with exit_code %d\n", exit_code);
    running = 0;
  }
  else if (strcmp(command, "") != 0)
  {
    // -------------- Add structure to commands --------------------------------
    struct command_struct{
      char *options[10];
    } sub_commands[1];
    // Simplified code, there would be a dynamic amount of sub_commands
    // and further logic to handle pipes and < > >>

    // initialize first command, would work dynamically
    sub_commands[0].options[0] = command;
    sub_commands[0].options[1] = NULL;

    int status;
    int pid = fork();
    if (pid == 0) {
      execvp(sub_commands[0].options[0], sub_commands[0].options);
      perror("Error: Reached code after execvp\n");
    } else if (pid < 0) {
      perror("Cannot fork!\n");
    }
    wait(&status);
  }
}


int main(int argc, char *argv[])
{
  cwd[0] = '/';

  do
  {
    printf("\n%s %s%s", "SHELL:", cwd, "> ");
    fgets(buffer, 255, stdin);
    buffer[255] = 0;
    handle_command(buffer, 256);
    for (size_t a = 0; a < 256; a++)
      buffer[a] = 0;

  } while (running);

  return exit_code;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int运行=1;
int exit_code=0;
char-cwd[256];
char命令[256];
字符args[10][256];
字符缓冲区[256]uuu属性_uuu((对齐(4096));
void handle_命令(char*buffer,int buffer_size)
{
int c=0;
int argscont=-1;
int lastIndex=0;
对于(c=0;c10)
{
argscont=10;
printf(“参数计数限制为10(无动态内存分配),所有其他参数将被忽略\n”);
打破
}
如果(缓冲区[c]='\r'| |缓冲区[c]='\n'| |缓冲区[c]='')
{
如果(argsCount==-1)
{
memcpy(命令,缓冲区+lastIndex,c-lastIndex);
命令[c-lastIndex]=0;
}
其他的
{
memcpy(args[argsCount],buffer+lastIndex,c-lastIndex);
args[argsCount][c-lastIndex]=0;
}
argscont++;
lastIndex=c+1;
}
}
如果(strcmp(命令,“退出”)==0)
{
c=4;
while(缓冲区[c]='')
C++;
退出代码=atoi(&buffer[c]);
printf(“退出Shell,退出代码为%d\n”,退出代码);
运行=0;
}
否则如果(strcmp(命令“”)=0)
{
//------将结构添加到命令--------------------------------
结构命令{
字符*选项[10];
}sub_命令[1];
//简化代码后,将有大量动态的sub_命令
//以及处理管道和<>>>
//初始化第一个命令,将动态工作
sub_命令[0]。选项[0]=命令;
sub_命令[0]。选项[1]=NULL;
智力状态;
int-pid=fork();
如果(pid==0){
execvp(子命令[0]。选项[0],子命令[0]。选项);
perror(“错误:到达execvp后的代码\n”);
}否则如果(pid<0){
perror(“无法分叉!\n”);
}
等待(&状态);
}
}
int main(int argc,char*argv[])
{
cwd[0]='/';
做
{
printf(“\n%s%s%s”,“SHELL:”,cwd“>”;
fgets(缓冲区,255,标准输入);
缓冲区[255]=0;
handle_命令(缓冲区,256);
对于(大小a=0;a<256;a++)
缓冲区[a]=0;
}跑步时;
返回退出代码;
}
EDIT我必须指出,这段代码的一部分是在这个类中给出的


任何帮助都将不胜感激

running==0
时,操作代码只会退出
main()
do
循环

running=0仅在strcmp(命令,“退出”)==0时发生,并且不清楚通过字符串解析是否在
命令中加载了刚才的
“退出”
。注意:
command
不是按照每个
handle\u command()
调用干净地初始化的,并且
command
不需要是全局变量

fgets()
返回
NULL
并查看行处理时,调整代码以退出。建议:

do {
  printf("\n%s %s%s", "SHELL:", cwd, "> ");
  if (fgets(buffer, sizeof buffer, stdin) == NULL) {
    break; 
  }
  // lop off potential end-of-line character(s)
  buffer[strcspn(buffer,"\r\n")] = '\0';
  handle_command(buffer, sizeof buffer);
} while (running);

running==0
时,操作代码只会退出
main()
do
循环

running=0仅在strcmp(命令,“退出”)==0时发生,并且不清楚通过字符串解析是否在
命令中加载了刚才的
“退出”
。注意:
command
不是按照每个
handle\u command()
调用干净地初始化的,并且
command
不需要是全局变量

fgets()
返回
NULL
并查看行处理时,调整代码以退出。建议:

do {
  printf("\n%s %s%s", "SHELL:", cwd, "> ");
  if (fgets(buffer, sizeof buffer, stdin) == NULL) {
    break; 
  }
  // lop off potential end-of-line character(s)
  buffer[strcspn(buffer,"\r\n")] = '\0';
  handle_command(buffer, sizeof buffer);
} while (running);

你给了我们一些细节,但没有什么足以自信地回答这个问题。提供一个MCVE供我们检查。但是,我可以观察到,您在没有捕获错误条件方面存在问题。例如,如果
fgets()
无法读取字符串(可能是因为已到达
stdin
的末尾),则它将通过返回
NULL
来指示是否读取字符串,但您不查找这种情况。同样,如果您的
execvp()
失败,则子进程将脱离您提供的
if
块,并继续作为父shell的副本运行。顺便说一句,这样清理
缓冲区似乎没有用。
fgets
将添加一个训练'\0',因此这是浪费时间。您可以只在第一个位置放置一个“\0”,这样您就可以确保有一个空字符串,但是捕获
fgets
错误(正如@JohnBollinger所说)将防止此缓冲区的错误使用。建议
fgets(buffer,255,stdin);缓冲区[255]=0-->
if(fgets(buffer,sizeof buffer,stdin)==NULL)中断;缓冲区[strcspn(缓冲区,“\r\n”)]=0当@JohnBollinger指出这可能是一个EOF问题时,我同意他的观点。当您不处理
fgets
返回值时,您永远不会知道
stdin
已经结束(当然,对于
管道
),也会发生这种情况。在这种情况下,
fgets
立即返回,而不修改
buffer
,即em