2015-11-12 35 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$