[英]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.