簡體   English   中英

在 C 中設計 shell 以執行由邏輯和連接的命令的問題

[英]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的有效指針,但為nextNULL ,從而使該標記未處理。

您還注釋掉了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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM