将命令导入shell后,shell中的C无限循环
我目前正在尝试为一个类构建一个自定义shell。我能够毫无问题地执行从这个shell发出的命令,但是如果我将我的命令管道化到shell中,我将得到一个无限循环。我不知道为什么会发生这种情况。下面的示例将导致无限循环将命令导入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()无法从上次发出的命令中清
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