[英]Problem in designing a shell in C to execute commands connected by logical and
我正在用 C 编写一个简单的 shell 来执行像command1 & command2
这样的外部命令,这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
static char line[1024];
char *and, *or, *col;
char *arg[1024];
static char* skipwhite(char* s)
{
while (isspace(*s)) ++s;
return s;
}
void run(char *cmd)
{
*and='\0';
int stat;
cmd= skipwhite(cmd);
char *next= strchr(cmd, ' ');
int i=0;
printf("%s \n", cmd);
while(next!=NULL)
{
*next='\0';
arg[i]=cmd;:
i++;
cmd= skipwhite(next+1);
next= strchr(cmd, ' ');
}
//arg[i]='\0';
int shmid = shmget(66, sizeof(int), IPC_CREAT | 0777);
int *status=(int *)shmat(shmid, NULL, 0);
*status=1;
int pid=fork();
if(pid==0)
{
int *v=(int *)shmat(shmid, NULL, 0);
if(execvp(arg[0], arg)==-1)
{
*v=0;
_exit(EXIT_FAILURE);
}
}
else
{
waitpid(pid, &stat, 0);
if(*status==0)
exit(0);
//printf("Trying to execute 2nd command\n");
cmd=and+1;
printf("%s \n", cmd);
and = strchr(cmd, '&');
if(and==NULL)
{
cmd= skipwhite(cmd);
next = strchr(cmd, ' ');
i=0;
while(next!=NULL)
{
*next='\0';
arg[i]=cmd;
i++;
cmd= skipwhite(next+1);
next= strchr(cmd, ' ');
}
arg[i]=cmd;
//arg[i+1]='\0';
if(execvp(arg[0], arg)==-1)
_exit(EXIT_FAILURE);
return;
}
else
run(cmd);
}
}
int main()
{
int status, pid;
printf("SIMPLE SHELL made by me. Type 'exit' or send EOF to exit.\n");
while(1)
{
printf("$> ");
fflush(NULL);
if(!fgets(line, 1024, stdin))
return 0;
char *cmds= line;
if(strcmp(cmds, "exit")==0)
exit(0);
and= strchr(cmds, '&');
or= strchr(cmds, '|');
col= strchr(cmds, ';');
if(and!=NULL)
{
pid=fork();
if(pid==0)
run(cmds);
else
waitpid(pid, &status, 0);
}
}
return 0;
}
我的动机是:
每当 shell 接收到外部命令时,它就会派生自己,比如新进程是 1 并且命令是command1 & command2
。 1 再次分叉自己执行 command1 和 command2。 如果command1
成功执行,则只为command2
创建一个新进程,否则不会。
问题是,即使最后一条命令是正确的,也永远不会执行。 我无法弄清楚代码中的问题。
如果需要任何信息,请在下面发表评论。
在这个循环中
while(next!=NULL)
{
*next='\0';
arg[i]=cmd;:
i++;
cmd= skipwhite(next+1);
next= strchr(cmd, ' ');
}
//arg[i]='\0';
您将字符串的所有部分复制到arg
除了最后一部分。
对于命令行中的最后一个标记,如果标记后没有额外空间,您将获得指向cmd
的有效指针,但为next
为NULL
,从而使该标记未处理。
您还注释掉了execv
系列函数所需的arg
数组的execv
。
您可能会重新设计循环:
while(cmd && *cmd) {
arg[i++]=cmd;
if (next) {
*next='\0';
cmd = skipwhite(next+1);
next = strchr(cmd, ' ');
}
else {
cmd = NULL;
}
}
arg[i]='\0';
关于额外问题的更新:
您在命令末尾有一个'\\n'
,因为您在阅读命令行后没有将其砍掉。 函数fgets
将整行读入缓冲区,直到(并包括) '\\n'
缓冲区足够大。
您只需要在调用fgets
后立即将其删除:
size_t len = strlen(line);
if (line[len-1] == '\n')
line[len-1] = 0;
或者
line[strlen(line)-1] = 0;
如果您为命令输入 1023 个字符,其中'\\n'
不能存储在缓冲区中,则第一个版本也可以正常工作。
只有当您输入的字符少于 1023 个时,第二个版本才能正常工作。 对于最大长度命令,它将杀死最后一个字符。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.