[英]exit command does not work properly in my own shell
I wrote a shell for an assignment and it works correctly, but there is a small run time error which i can not figure out. 我为任务编写了一个Shell,它可以正常工作,但是有一个很小的运行时错误,我无法弄清楚。 When the user enter the command 'exit' through the shell it should come out of newly created shell.
当用户通过外壳输入命令“ exit”时,它应该来自新创建的外壳。 But the problem is I have to type the command 'exit' several times to quit the shell.
但是问题是我必须多次键入命令“ exit”才能退出外壳。 If someone can help me it will be a great pleasure for me!
如果有人可以帮助我,那将是我的荣幸! Thanks all!
谢谢大家!
#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);
}
}
}
Like the cd
command, the exit
command has to be interpreted by the shell as a built-in; 像
cd
命令一样, exit
命令必须由shell解释为内置命令。 it must exit the loop or call the exit()
function directly. 它必须退出循环或直接调用
exit()
函数。 However, it also appears that should be happening. 但是,这似乎也应该发生。 Note that using
strcoll()
is a little unusual; 注意,使用
strcoll()
有点不寻常。 normally, strcmp()
is sufficient. 通常,
strcmp()
就足够了。
You should report problems if execvp()
returns — and you must make sure the sub-shell exits so that you don't have multiple shell processes reading the input simultaneously. 如果
execvp()
返回,则应该报告问题,并且必须确保退出子外壳程序,这样就不会有多个外壳程序进程同时读取输入。 I'm left wondering if this problem is occurring, and that's why you have to type exit
multiple times. 我不知道是否会发生此问题,这就是为什么您必须多次键入
exit
的原因。
You also need to check that fgets()
did not report an error. 您还需要检查
fgets()
没有报告错误。 It always null terminates its input; 它总是null终止其输入; your code does not zap the newline (you'd need
strlen(buffer)-1
instead of sizeof(buffer)-1
). 您的代码不会换行(您需要
strlen(buffer)-1
而不是sizeof(buffer)-1
)。
The code that reads and sets PATH
is wrong. 读取和设置
PATH
的代码是错误的。 getenv("PATH")
returns a pointer to the first character after the PATH=
part; getenv("PATH")
返回指向PATH=
部分后的第一个字符的指针; you then use that to 'set' the environment. 然后使用它来“设置”环境。 Fortunately for you, the average value for PATH does not contain anything that looks like
VAR=value
, so it is functionally a no-op (though the information is probably copied into the environment, where it makes a mess without causing any major harm). 对您来说幸运的是,PATH的平均值不包含看起来像
VAR=value
任何内容,因此它在功能上是无操作的(尽管信息很可能被复制到环境中,不会造成任何重大伤害,但会造成混乱) 。
Your code indentation scheme is rococo at best — mostly, it is just woefully inconsistent. 您的代码缩进方案充其量是洛可可式的-大多数情况下,它只是可悲的不一致。 Please be consistent!
请保持一致! The spacing of the lines in the code was also extremely erratic.
代码中的行间距也非常不稳定。 When you're adding code in SO, do not use tabs, do use 4 spaces per indent level, do highlight a block of code that is left justified and use the
{}
button above the edit box to indent it as code. 在SO中添加代码时,请勿使用制表符,每个缩进级别使用4个空格,突出显示左对齐的代码块,并使用编辑框上方的
{}
按钮将其缩进为代码。 This also means you don't need to add blank lines to the code. 这也意味着您无需在代码中添加空白行。
You aren't closing enough file descriptors. 您没有关闭足够的文件描述符。 When you use
dup()
(or dup2()
) to duplicate a pipe to standard input or standard output, you have to close both of the file descriptors returned by pipe()
. 当您使用
dup()
(或dup2()
)将管道复制到标准输入或标准输出时,必须关闭pipe()
返回的两个文件描述符。
On Linux, using fflush(stdin)
is undefined behaviour, AFAIK. 在Linux上,使用
fflush(stdin)
是未定义的行为AFAIK。 It is defined on Windows, but not on POSIX systems. 它在Windows上定义,但在POSIX系统上未定义。
You don't check that your chdir()
system call works. 您无需检查
chdir()
系统调用是否有效。
Trying your code, I did get one runaway prompt. 尝试您的代码,我确实收到一个失控的提示。 Unfortunately, I couldn't remember or see what triggered the runaway.
不幸的是,我不记得或看不到是什么引发了失控。 The code below is mostly sanitized and seems to behave.
下面的代码大部分经过了清理,并且似乎可以正常运行。 I've annotated some critical changes — and not others.
我已经注释了一些重要的更改,而没有其他注释。 One of the things you should be doing for your own benefit is including trace like the
dump_cmd()
function so you can see what your program is doing. 为了自己的利益,应该做的一件事是包括
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++);
}
I'm not keen on the code, but it does seem mostly sane. 我并不热衷于代码,但是看起来确实很理智。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.