gpt4 book ai didi

c - exit 命令在我自己的 shell 中不能正常工作

转载 作者:太空宇宙 更新时间:2023-11-04 11:23:48 26 4
gpt4 key购买 nike

我为一个作业编写了一个 shell,它工作正常,但是有一个我无法弄清楚的小运行时错误。当用户通过 shell 输入命令“exit”时,它应该从新创建的 shell 中退出。但问题是我必须多次键入命令“exit”才能退出 shell。如果有人可以帮助我,那将是我的荣幸!谢谢大家!

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

char* cmndtkn[256];
char buffer[256];
char* path=NULL;
char pwd[128];

int main(){

//setting path variable
char *env;
env=getenv("PATH");
putenv(env);

system("clear");

printf("\t MY OWN SHELL !!!!!!!!!!\n ");
printf("_______________________________________\n\n");

while(1){

fflush(stdin);
getcwd(pwd,128);
printf("[MOSH~%s]$",pwd);

fgets(buffer,sizeof(buffer),stdin);
buffer[sizeof(buffer)-1] = '\0';

//tokenize the input command line
char* tkn = strtok(buffer," \t\n");
int i=0;
int indictr=0;

// loop for every part of the command
while(tkn!=NULL)
{
if(strcoll(tkn,"exit")==0 ){
exit(0);
}

else if(strcoll(buffer,"cd")==0){

path = buffer;
chdir(path+=3);}

else if(strcoll(tkn,"|")==0){

indictr=i;}
cmndtkn[i++] = tkn;
tkn = strtok(NULL," \t\n");

}cmndtkn[i]='\0';

// execute when command has pipe. when | command is found indictr is greater than 0.
if(indictr>0){

char* leftcmnd[indictr+1];
char* rightcmnd[i-indictr];
int a,b;

for(b=0;b<indictr;b++)
leftcmnd[b]=cmndtkn[b];

leftcmnd[indictr]=NULL;

for(a=0;a<i-indictr-1;a++)
rightcmnd[a]=cmndtkn[a+indictr+1];

rightcmnd[i-indictr]=NULL;

if(!fork())
{
fflush(stdout);
int pfds[2];
pipe(pfds);

if(!fork()){

close(1);
dup(pfds[1]);
close(pfds[0]);
execvp(leftcmnd[0],leftcmnd);
}
else{

close(0);
dup(pfds[0]);
close(pfds[1]);
execvp(rightcmnd[0],rightcmnd);
}

}else wait(NULL);

//command not include pipe

}else{

if(!fork()){
fflush(stdout);
execvp(cmndtkn[0],cmndtkn);

}else wait(NULL);

}

}

}

最佳答案

cd 命令一样,exit 命令必须由 shell 解释为内置命令;它必须退出循环或直接调用 exit() 函数。然而,这似乎也应该发生。请注意,使用 strcoll() 有点不寻常;通常,strcmp() 就足够了。

如果 execvp() 返回,您应该报告问题 — 并且您必须确保子 shell 退出,这样您就不会有多个 shell 进程同时读取输入。我想知道是否会出现此问题,这就是为什么您必须多次键入 exit 的原因。

您还需要检查fgets() 没有报错。它总是 null 终止它的输入;您的代码不会换行(您需要 strlen(buffer)-1 而不是 sizeof(buffer)-1)。

读取和设置PATH的代码是错误的。 getenv("PATH") 返回指向 PATH= 部分之后第一个字符的指针;然后你用它来“设置”环境。对你来说幸运的是,PATH 的平均值不包含任何类似 VAR=value 的东西,所以它在功能上是一个空操作(尽管信息可能被复制到环境中,在那里它使乱而不造成任何重大伤害)。

您的代码缩进方案充其量只是洛 cocoa 式的——大多数情况下,它只是非常不一致。请保持一致!代码中的行间距也非常不稳定。当您在 SO 中添加代码时,不要使用制表符,每个缩进级别使用 4 个空格,突出显示左对齐的代码块并使用 {} 编辑框上方的按钮将其缩进为代码。这也意味着您不需要在代码中添加空行。

您没有关闭足够的文件描述符。当您使用 dup()(或 dup2())将管道复制到标准输入或标准输出时,您必须关闭两者 pipe() 返回的文件描述符。

在 Linux 上,使用 fflush(stdin) 是未定义的行为,AFAIK。它是在 Windows 上定义的,但不是在 POSIX 系统上定义的。

您没有检查您的 chdir() 系统调用是否正常工作。


尝试你的代码,我确实得到了一个失控提示。不幸的是,我不记得或看到是什么引发了失控。下面的代码大部分都经过清理并且似乎可以正常运行。我已经注释了一些关键的变化——而不是其他的。为了您自己的利益,您应该做的一件事是包括像 dump_cmd() 函数这样的跟踪,这样您就可以看到您的程序在做什么。

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

char *cmndtkn[256];
char buffer[256];
char *path = NULL;
char pwd[128];

static void dump_cmd(char **argv);

int main(void)
{
/*
//setting path variable
char *env;
env=getenv("PATH");
putenv(env);
system("clear");
*/

printf("\t MY OWN SHELL !!!!!!!!!!\n ");
printf("_______________________________________\n\n");

while (1)
{
//fflush(stdin);
getcwd(pwd, 128);
printf("[MOSH~%s]$", pwd);

if (fgets(buffer, sizeof(buffer), stdin) == 0)
{
putchar('\n');
break;
}
//buffer[sizeof(buffer)-1] = '\0';
buffer[strlen(buffer)-1] = '\0';

//tokenize the input command line
char *tkn = strtok(buffer, " \t\n");
int i = 0;
int indictr = 0;

// loop for every part of the command
while (tkn != NULL)
{
if (strcoll(tkn, "exit") == 0)
{
printf("Got: exit\n");
fflush(stdout);
exit(0);
}
else if (strcoll(tkn, "cd") == 0) // Was buffer, not tkn
{
printf("Got: cd (%s)\n", buffer + 3);
fflush(stdout);
path = buffer;
chdir(path += 3);
}
else if (strcoll(tkn, "|") == 0)
{
indictr = i;
}
cmndtkn[i++] = tkn;
tkn = strtok(NULL, " \t\n");
}
cmndtkn[i] = 0;

// execute when command has pipe. when | command is found indictr is greater than 0.
if (indictr > 0)
{
char *leftcmnd[indictr+1];
char *rightcmnd[i-indictr];
int a, b;

for (b = 0; b < indictr; b++)
leftcmnd[b] = cmndtkn[b];

leftcmnd[indictr] = NULL;

for (a = 0; a < i-indictr-1; a++)
rightcmnd[a] = cmndtkn[a+indictr+1];

rightcmnd[i-indictr-1] = NULL; // Did not include -1

if (!fork())
{
fflush(stdout);
int pfds[2];
pipe(pfds);

if (!fork())
{
dump_cmd(leftcmnd);
close(1);
dup(pfds[1]);
close(pfds[0]);
close(pfds[1]);
execvp(leftcmnd[0], leftcmnd);
fprintf(stderr, "failed to execvp() %s\n", leftcmnd[0]);
exit(1);
}
else
{
dump_cmd(rightcmnd);
close(0);
dup(pfds[0]);
close(pfds[0]);
close(pfds[1]);
execvp(rightcmnd[0], rightcmnd);
fprintf(stderr, "failed to execvp() %s\n", rightcmnd[0]);
exit(1);
}
}
else
wait(NULL);

}
else
{
//command does not include pipe
if (!fork())
{
dump_cmd(cmndtkn);
fflush(stdout);
execvp(cmndtkn[0], cmndtkn);
fprintf(stderr, "failed to execvp() %s\n", cmndtkn[0]);
exit(1);
}
else
wait(NULL);
}
}

return 0;
}

static void dump_cmd(char **argv)
{
int i = 0;
fprintf(stderr, "%d: Command:\n", (int)getpid());
while (*argv != 0)
fprintf(stderr, "%d: %d: [[%s]]\n", (int)getpid(), i++, *argv++);
}

我对代码不感兴趣,但它看起来很正常。

关于c - exit 命令在我自己的 shell 中不能正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16206260/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com