2015-11-12 95 views
-2

我想創建一個子進程運行linux命令的shell(在execvp的幫助下),比如「ls」等。我也希望能夠運行帶有諸如「ls -a「或」ls -l/tmp「父母必須等待孩子用」waitpid「執行給定的命令。 當我試圖用「ls -a」運行shell時,它將它作爲2個單獨的命令。輸出:LS $ -a $從子進程運行命令

#include "stdio.h" 
#include "unistd.h" 
#include "stdlib.h" 

int main(int argc, char **argv) 
{ 
    char input[64]; 
    pid_t pid; 
    char *status; 
    char *args[64]; 
    char **next = args; 
    char *temp; 

    while (1) { 
     printf("$"); 
     fgets(input,"exit",stdin); 
     if (strcmp(input, "exit") == 0) { 
     exit(0) 
     } 
     pid = fork(); 

     if (pid == 0) { 
      //child 

      *temp = strtok(input, " "); 


      while (temp != NULL) { 
       *next++ = temp; 
       *temp = strtok(NULL, " "); 
      } 


      if (execvp(args[0], args) == -1) { 
       perror("Execvp Error"); 
      } 
      exit(0); 

     }else if (pid < 0) { 
      printf("error during fork"); 
     }else { 
      //parent 
      waitpid(pid, &status, 0); 
     } 
    } 
} 
+2

大。你有問題嗎? –

+0

你以'while(strcmp(input,「exit」))''開始,但是'input'沒有任何內容。之後,你讀'輸入'和叉子。即使用戶輸入「退出」(讓我們說)。全局邏輯不是「邏輯」的。 – hexasoft

+0

每當我運行程序,我不能看到我的命令的輸出......如果在那裏放置一個錯誤的命令,它不會顯示任何錯誤 – purkavlos

回答

-2

我認爲purkavlos這裏給我們以一個示例代碼(這是沒有充分發揮作用還)爲我們展示他身後經過的子進程運行命令的邏輯..糾正部分代碼不是很有幫助..

解決方案: 通過使用gets()而不是scanf()將解決您的第一個問題,以便您可以接受帶有空格的字符串,如Paul所說。 檢查是否適用於您,因爲我可以看到標記化是正確的。 之後,該命令應該運行,但我不知道輸出,你通過孩子嗎?

+0

這是一條評論,而不是答案。如果你想成爲「非常有幫助」的人,建議有人使用'gets()'不是做這件事的方法。 –

+0

意思是fgets兄弟... – yakushi

+0

夥計們請停止downvoting每個人。這是我的第一篇文章,我試圖做你告訴我的。 無論如何仍然當我試圖運行與「ls -a」的外殼它需要它作爲2個單獨的指揮官 輸出:ls $ -a $ – purkavlos

0

如果您編寫了一些幫助函數並提出了合適的數據結構,它就變得微不足道了。例如:

main.c

#define _POSIX_C_SOURCE 200809L 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include "stringlist.h" 
#include "io.h" 


int main(void) 
{ 
    StringList list = NULL; 
    get_input(&list); 

    while (strcmp(stringlist_string_at_index(list, 0), "exit")) { 
     pid_t p = fork(); 

     if (p < 0) { 
      perror("fork() error"); 
      exit(EXIT_FAILURE); 
     } 
     else if (p == 0) { 
      char ** args = stringlist_raw_list(list); 
      execvp(args[0], args); 
      switch (errno) { 
       case EACCES: 
        printf("Error: access denied.\n"); 
        break; 

       case ENOENT: 
        printf("Error: file not found.\n"); 
        break; 

       default: 
        printf("Error: couldn't fulfill request.\n"); 
        break; 
      } 
      exit(EXIT_FAILURE); 
     } 
     else { 
      int status; 
      waitpid(p, &status, 0); 
     } 

     get_input(&list); 
    } 

    stringlist_destroy(list); 
    return EXIT_SUCCESS; 
} 

與助手文件:

io.h

#ifndef IO_H 
#define IO_H 

#include "stringlist.h" 

void get_input(StringList * list); 

#endif  /* IO_H */ 

io.c

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include "io.h" 
#include "stringlist.h" 


#define MAX_INPUT_LENGTH 256 

static void get_input_line(char * buffer, const size_t buffer_size); 
static void output_prompt(void); 
static StringList tokenize_input(void); 


/* Prompts for and gets input from standard input. 
* 
* If the StringList pointed to by `list` is not NULL, it will 
* be destroyed. The StringList pointed to by `list` will be 
* modified to point to a new StringList created from the input. 
* If no input is entered, function will prompt for it again. 
* 
* Note: the input is tokenized purely by space characters, so input 
* resembling: 
* 
*  cat "Filename with spaces" 
* 
* will return four tokens, not two. This simple method of tokenizing 
* will be unsuitable for many applications. 
*/ 

void get_input(StringList * list) 
{ 
    if (*list) { 
     stringlist_destroy(*list); 
    } 

    do { 
     output_prompt(); 
     *list = tokenize_input(); 
    } while (stringlist_length(*list) == 0); 
} 


/* Gets a line of input from standard input. 
* 
* Function strips the trailing newline, if present, and 
* exits the program on error. 
*/ 

static void get_input_line(char * buffer, const size_t buffer_size) 
{ 
    if (!fgets(buffer, buffer_size, stdin)) { 
     fprintf(stderr, "error getting input\n"); 
     exit(EXIT_FAILURE); 
    } 

    const size_t len = strlen(buffer); 
    if (len > 0 && buffer[len - 1] == '\n') { 
     buffer[len - 1] = 0; 
    } 
} 


/* Outputs the shell prompt */ 

static void output_prompt(void) 
{ 
    printf("shell$ "); 
    fflush(stdout); 
} 


/* Gets a line of input from standard input and tokenizes it */ 

static StringList tokenize_input(void) 
{ 
    StringList list = stringlist_create(); 

    char input[MAX_INPUT_LENGTH]; 
    get_input_line(input, MAX_INPUT_LENGTH); 

    char * t = strtok(input, " "); 
    while (t) { 
     stringlist_add(list, t); 
     t = strtok(NULL, " "); 
    } 

    return list; 
} 

stringlist.h

#ifndef STRING_LIST_H 
#define STRING_LIST_H 

#include <stddef.h> 
#include <stdbool.h> 

typedef struct stringlist * StringList; 

StringList stringlist_create(void); 
bool stringlist_delete_last(StringList list); 
void stringlist_destroy(StringList list); 
size_t stringlist_length(StringList list); 
char * stringlist_string_at_index(StringList list, const size_t index); 
char ** stringlist_raw_list(StringList list); 
void stringlist_add(StringList list, const char * str); 

#endif  /* STRING_LIST_H */ 

stringlist.c

#define _POSIX_C_SOURCE 200809L 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <stdbool.h> 
#include "stringlist.h" 

#define DEFAULT_LIST_SIZE 8 

struct stringlist { 
    char ** list;  /* Pointer to list of strings  */ 
    size_t size;  /* Current capacity of list  */ 
    size_t top;   /* Lowest empty element of list */ 
}; 


/* Creates a new list of default capacity */ 

StringList stringlist_create(void) 
{ 
    struct stringlist * new_list = malloc(sizeof *new_list); 
    if (!new_list) { 
     perror("memory allocation failed"); 
     exit(EXIT_FAILURE); 
    } 

    new_list->size = DEFAULT_LIST_SIZE; 
    new_list->top = 0; 

    char ** list = calloc(new_list->size, sizeof *list); 
    if (!list) { 
     perror("memory allocation failed"); 
     exit(EXIT_FAILURE); 
    } 

    new_list->list = list; 

    return new_list; 
} 


/* Deletes the last string in the list. 
* 
* Returns false if the list was empty, otherwise true. 
*/ 

bool stringlist_delete_last(StringList list) 
{ 
    if (list->top) { 
     list->top -= 1; 
     free(list->list[list->top]); 
     list->list[list->top] = NULL; 
     return true; 
    } 
    return false; 
} 


/* Destroys the list and frees all resources */ 

void stringlist_destroy(StringList list) 
{ 
    while (stringlist_delete_last(list)) { 
     ; 
    } 
    free(list->list); 
    free(list); 
} 


/* Returns the number of strings currently in the list */ 

size_t stringlist_length(StringList list) 
{ 
    return list->top; 
} 


/* Returns the string at the specified index of the list */ 

char * stringlist_string_at_index(StringList list, const size_t index) 
{ 
    return list->list[index]; 
} 


/* Returns a pointer to the raw list of strings. 
* 
* This raw list will be NULL-terminated, that is, if the raw 
* list contains `length` strings, then raw_list[length] == NULL. 
* This makes the raw list suitable for passing, for instance, to 
* execv() and friends. 
*/ 

char ** stringlist_raw_list(StringList list) 
{ 
    return list->list; 
} 


/* Adds a string to the list. 
* 
* The raw list will be dynamically resized, if necessary. 
*/ 

void stringlist_add(StringList list, const char * str) 
{ 
    if (list->top + 1 >= list->size) { 
     char ** new_array = realloc(list->list, 
            list->size * 2 * sizeof *new_array); 
     if (!new_array) { 
      perror("memory allocation failed"); 
      exit(EXIT_FAILURE); 
     } 
     list->list = new_array; 
     list->size *= 2; 
    } 

    char * duped = strdup(str); 
    if (!duped) { 
     perror("memory allocation failed"); 
     exit(EXIT_FAILURE); 
    } 

    list->list[list->top] = duped; 
    list->top += 1; 
    list->list[list->top] = NULL; 
} 

這增加了一些錯誤檢查空的輸入,並響應以更有意義的方式失敗execvp()電話。

樣品會話:

[email protected]:~/Documents/src/sandbox/simple_shell$ ./ss 
shell$ 
shell$ 
shell$ ./Fakefile 
Error: file not found. 
shell$ ./Makefile 
Error: access denied. 
shell$ ls -alF 
total 96 
drwxr-xr-x 12 Paul staff 408 Nov 12 21:18 ./ 
drwxr-xr-x 6 Paul staff 204 Nov 12 20:42 ../ 
-rw-r--r-- 1 Paul staff 368 Nov 12 21:07 Makefile 
-rw-r--r-- 1 Paul staff 2016 Nov 12 21:18 io.c 
-rw-r--r-- 1 Paul staff 113 Nov 12 21:10 io.h 
-rw-r--r-- 1 Paul staff 2240 Nov 12 21:18 io.o 
-rw-r--r-- 1 Paul staff 1214 Nov 12 21:08 main.c 
-rw-r--r-- 1 Paul staff 1608 Nov 12 21:11 main.o 
-rwxr-xr-x 1 Paul staff 10032 Nov 12 21:18 ss* 
-rw-r--r-- 1 Paul staff 2799 Nov 12 20:52 stringlist.c 
-rw-r--r-- 1 Paul staff 504 Nov 12 20:53 stringlist.h 
-rw-r--r-- 1 Paul staff 2492 Nov 12 21:11 stringlist.o 
shell$ ps 
    PID TTY   TIME CMD 
75221 ttys002 0:00.19 -bash 
75678 ttys002 0:00.00 ./ss 
shell$ echo Hello, world! 
Hello, world! 
shell$ cat "Tokenizing input with spaces is generally bad.txt" 
cat: "Tokenizing: No such file or directory 
cat: input: No such file or directory 
cat: with: No such file or directory 
cat: spaces: No such file or directory 
cat: is: No such file or directory 
cat: generally: No such file or directory 
cat: bad.txt": No such file or directory 
shell$ exit 
[email protected]:~/Documents/src/sandbox/simple_shell$