我为一个赋值编写了一个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);
}
}
}
答案 0 :(得分:1)
与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
的东西,因此它在功能上是一个无操作(虽然信息可能被复制到环境中,在那里它会造成混乱而不会导致任何重大问题伤害)。
你的代码缩进方案充其量只是洛可可 - 大多数情况下,它只是非常不一致。请保持一致!代码中的行间距也非常不稳定。当您在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++);
}
我并不热衷于代码,但看起来确实很健全。