用C编写的Shell只执行一次

时间:2015-11-28 12:20:48

标签: c linux shell pipe

我被要求在C中编写一个shell代码,它将执行类似的命令 无管道的lspwdls -lls -l -lals -l /tmp等。

以下是它的表现。

  1. 尝试单字命令可以很好地工作(例如lspwdpstreepstime),无论多少次我输入它们。

  2. 尝试使用选项的一个命令只能在第一次使用,然后我得到一个未找到的"命令"每次我重新输入它。 (例如ls -l)。

  3. 尝试使用选项和路径的一个命令,如果它是我在shell上键入的第一个命令(例如ls -l /tmp),并且如果它是第一个命令,则执行任意多次。如果我先输入ls然后再输入ls -l /tmp,我会收到一个找不到的命令。

  4. 这是我的更新代码(它不是一个小代码):

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #define N 1000 // array size
    #define TRUE 1
    #define FALSE 0
    typedef bool;
    
    struct Buffer // used to store search_path because of strcat erros with simple array
    {
        char cache1[N];
    }buffer[N];
    
    struct Directories // Storing the directories
    {
                    char dir[N];
    }directories[N];
    
    struct Words // Storing the 2 words entered
    {
                    char w[N];
    }words[N];
    
    char options[N] = {0}; // store all -x options here e.g -la -l -l -a
    int path_count = 0; // # of directories in $PATH
    bool terminate = TRUE;  // bool variable to check for program termination
    char input[N] = {0}; // our input command
    char file[N] = {0};
    int words_typed = 0;            // # of words typed.
    int options_count = 1,i;    // # of options in options table
    int dir_count = 0;        // # of directories
    int word_processed;       // which word we are currently in
    int cursor;       // cursor position in each word
    int length;       // # of characters typed.
    
    
    
    
    
    int main()
    {
        char *search_path = {0}; // What $ PATH returns
        search_path = strtok(getenv("PATH"),":");
        while (search_path!=NULL) // path scanning method
        {
            strcat(buffer[path_count].cache1,search_path); // buffer.cache1 = search_path
            strcat(buffer[path_count].cache1,"/"); // buffer.cache1 = search_path/
            path_count++;
            search_path = strtok(NULL,":"); // Start scanning next path
        }
        while(terminate)
        {
             func_body();
        }
        return 0;
    }
    
    
    
    int func_body ()
    {
            do
            {
                printf("$"); // $ before each input command
                gets(input); // get input from user
            } while(strcmp(input,"") == 0); // printf $ every time user presses ENTER
            bool statement = (strcmp(input,"exit") == 0 );
            if (statement) // if user entered "exit"
                      terminate = FALSE; // while(0) terminates program
            else if (!statement) // if we dont want to exit,...
            {
                length = strlen(input); // # of characters typed.
                if (input[0] != ' ')  // Procedure of finding how many words the user has typed
                       words_typed+=1; // If the first character is not the 'space' key then it is a word,so the words_typed becomes 1
                i=1;
                while (i<length)
                {
                    if ((input[i-1] == ' ') && (input[i] != ' ')) 
                         words_typed+=1; // If the current character is not the 'space key' and the previous is, then we have a new word
                         i+=1;
                }
                   func_words();
                   func_directories();
                   func_command();
            }
    return 0;
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    int func_words()
    {
    
                i=0;
                while (i<words_typed)
                {
                    for (cursor=0; cursor<N; cursor++)
                    {
                        words[i].w[cursor] = '\0';  // initialize the array
                    }
                    i+=1;
                }
                word_processed = 0;
                cursor = 0;
                if (input[0] != ' ') // If the first character is not the 'space' key
                {
                    words[word_processed].w[cursor]=input[cursor]; // We input the first character of the first word in the struct
                    cursor+=1;
                }
                else 
                     word_processed = -1; // If the first character is indeed the 'space' key then h is downgraded to -1 because if doesn't it will cause problems
                i=1;
                while (i<length) // Counter i contains where we are on the command given by the user.For example on the string 'ls -l' character 's' is on number 1
                {
                    if ((input[i] != ' ') && (input[i-1] == ' '))
                    {
                        word_processed+=1;
                        cursor = 0; // begin the procedure for the other word of the string
                    }
                    if (input[i] != ' ')  // If the first character is not the 'space' key
                            words[word_processed].w[cursor] = input[i]; // We input the first character of the first word in the struct
                    cursor+=1;
                    i+=1;
                }
        return 0;
    }
    
    
    
    
    
    
    
    
    
    
    int func_directories()
    {
    
    
                i=0;
                do
                {
                    for (cursor=0; cursor<N; cursor++)
                    {
                        directories[i].dir[cursor] ='\0';  // initialize the array
                    }
                    i+=1;
                }while(i<words_typed);
                i=1;
                do
                {
                    if (words[i].w[0] == '-') // if user pressed '-'
                    {
                        for (cursor=1; cursor<strlen(words[i].w); cursor++)
                        {
                            options[options_count] = words[i].w[cursor]; // counting the times user pressed and store characters after '-' option
                            options_count+=1;
                        }
                        options[0]='-';
                    }
                    else // in case we dont have a -x command
                    {
                        for (cursor=0; cursor<strlen(words[i].w); cursor++)
                        {
                            directories[dir_count].dir[cursor]=words[i].w[cursor]; 
                        }
                        dir_count+=1;
                    }
                    i+=1;
                }while(i<words_typed);
         return 0;  
    }
    
    
    
    
    
    
    
    
    int func_command()
    {
                pid_t pid;
                int temp = dir_count;
                i = 0;
                do // wont work with while loop
                {
                    strcpy(file,directories[i].dir); // file = directory
                    if (words_typed == 1)  // if 1 word is typed eg. ls
                           execute(words[0].w,NULL,NULL); // only 1 argument needed
                    else if ((options[1] != ' ') && (temp == 0)) // if user enter command x -x e.g ls -l
                           execute(words[0].w,options,NULL); // options has all the -x options user typed e.g -l -l -a
                    else if ((options[1] == ' ') && (temp != 0)) // if user enter command x -x /directory e.g ls -l /tmp
                           execute(words[0].w,file,NULL);
                    else 
                           execute(words[0].w,options,file); // most complex command
                    dir_count-=1;
                    i+=1;
                }while (dir_count > 0);
                words_typed=0;
                return 0;
    }
    
    
    
    
    
    
    
    
    
    
    
    int execute(char first_word[],char all_array[],char words[])
    {
        int counter,status;
        pid_t pid;
        for (counter=0;counter<path_count;counter++)
        {
            char command_path[N] = {0}; 
            strcat(command_path,buffer[counter].cache1); // command_path = search_path
            strcat(command_path,first_word); // command_path = search_path/command
            if(fopen(command_path,"r") != NULL)
            {
                pid = fork();
                if (pid==0) // child process
                     execlp(command_path,first_word,all_array,words,NULL);
                if (pid>0) // parent process
                     waitpid(pid,&status,0);
                // if pid < 0 -> error
            }
        }
        return 0;
    }
    

    问题是我设法让它运行多次(参见here),但是因为我开始使结构和变量全局化,所以在{中添加函数而不是整个代码{1}},它似乎只是第一次运行,然后执行除main()之外的其他命令。

2 个答案:

答案 0 :(得分:1)

事实证明,执行函数中的单词数组包含一个奇怪的字符,但它的长度为零,您需要进行一些更改!更新您的执行功能,如下所示

int execute(char first_word[],char all_array[],char wrds[])
{
    int counter,status;
    pid_t pid;

    for (counter=0;counter<path_count;counter++)
    {
        char command_path[N] = {0}; 
        strcat(command_path,buffer[counter].cache1); // command_path = search_path
        strcat(command_path,first_word); // command_path = search_path/command
        //printf("%s\n",command_path);
        if(fopen(command_path,"r") != NULL)
        {
            pid = vfork();
            if (pid==0){ // child process
            //printf("%s\n",command_path);
            if(wrds!=NULL){
                if(strlen(wrds)==0){wrds=NULL;}}
                 execlp(command_path,first_word,all_array,wrds,NULL);}
            if (pid>0) // parent process
                 waitpid(pid,&status,0);
            // if pid < 0 -> error
        }
    }
    return 0;
}

每次用户输入新命令时,您需要在第二个do-while循环的func_directories()方法中将options_count更新为1

if (words[i].w[0] == '-') // if user pressed '-'
            {//line 165
                options_count=1;
                //rest of the code

答案 1 :(得分:0)

发现错误。我应该在func_command()的末尾重新初始化我的所有全局变量。

int func_command()
{
            pid_t pid;
            int temp = dir_count;
            i = 0;
            do // wont work with while loop
            {
                strcpy(file,directories[i].dir); // file = directory
                if (words_typed == 1)  // if 1 word is typed eg. ls
                       execute(words[0].w,NULL,NULL); // only 1 argument needed
                else if ((options[1] != ' ') && (temp == 0)) // if user enter command x -x e.g ls -l
                       execute(words[0].w,options,NULL); // options has all the -x options user typed e.g -l -l -a
                else if ((options[1] == ' ') && (temp != 0)) // if user enter command x -x /directory e.g ls -l /tmp
                       execute(words[0].w,file,NULL);
                else 
                       execute(words[0].w,options,file); // most complex command
                dir_count-=1;
                i+=1;
            }while (dir_count > 0);
            i=0,options[N] = '\0',words_typed = 0,options_count = 1,dir_count = 0,word_processed=0,cursor=0,str_length=0; // restore values because they are global
            return 0;
}