2016-10-26 2 views
1

У меня есть следующий код:C Shell для выполнения команд

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/wait.h> 
#include <string.h> 

void passe(char *ligne, char **argv) 
{ 
    while (*ligne != '\0') 
    { 
      while (*ligne == ' ' || *ligne == '\t' || *ligne == '\n') 
       *ligne++ = '\0'; 
      *argv++ = ligne; 
      while (*ligne != '\0' && *ligne != ' ' && *ligne != '\t' && *ligne != '\n') 
       ligne++; 
    } 
    *argv = '\0'; 
} 

void executer(char **argv) 
{ 
    pid_t pid; 
    int status; 

    if ((pid=fork()) == 0) 
    { 
      if (execvp(*argv, argv) < 0) 
      { 
       printf("*** ERREUR: exec echoué\n"); 
       exit(1); 
      } 
    } 
    wait(&status); 
} 

int main(void) 
{ 
    char ligne[1024]; 
    char *argv[64]; 

    while (1) 
    { 
      printf("Shell -> "); 
      scanf("%s",ligne); 
      printf("\n"); 
      passe(ligne, argv); 
      if (strcmp(argv[0], "exit") == 0) 
       exit(0); 
      executer(argv); 
    } 
    return 0; 
} 

Программа прекрасно работает, однако, когда я анализирую что-то вроде «пс -f» она retunrs «execvp echoué», поскольку код удаляет пробелы , Что я должен сделать, чтобы заставить его принимать команды с такими параметрами, как ps -f?

ответ

2

Вы должны использовать fgets() вместо scanf(). Поскольку fgets не удаляет пробелы со своего ввода. Функция scanf потребляет только входные данные до пробела. Например, если вы вводите «ps -f», scanf потребляет этот вход как «ps». Если вы пишете ps прямо на свой терминал, вы можете столкнуться с тем же исключением, что и ваше исключение в программе. Вы можете использовать fgets как средство чтения потоков, которое может быть потоком файлов или стандартным входным потоком (stdin). Я написал код, который решает вашу проблему. Вы можете проверить, как вы можете использовать.

/* ----------------------------------------------------------------- */ 
/* PROGRAM shell.c             */ 
/* This program reads in an input line, parses the input line  */ 
/* into tokens, and use execvp() to execute the command.    */ 
/* ----------------------------------------------------------------- */ 

#include <stdio.h> 
#include <sys/types.h> 

/* ----------------------------------------------------------------- */ 
/* FUNCTION parse:             */ 
/* This function takes an input line and parse it into tokens. */ 
/* It first replaces all white spaces with zeros until it hits a  */ 
/* non-white space character which indicates the beginning of an  */ 
/* argument. It saves the address to argv[], and then skips all  */ 
/* non-white spaces which constitute the argument.     */ 
/* ----------------------------------------------------------------- */ 

void parse(char *line, char **argv) 
{ 
    while (*line != '\0') {  /* if not the end of line ....... */ 
      while (*line == ' ' || *line == '\t' || *line == '\n') 
       *line++ = '\0';  /* replace white spaces with 0 */ 
      *argv++ = line;   /* save the argument position  */ 
      while (*line != '\0' && *line != ' ' && 
       *line != '\t' && *line != '\n') 
       line++;    /* skip the argument until ... */ 
    } 
    *argv = '\0';     /* mark the end of argument list */ 
} 

/* ----------------------------------------------------------------- */ 
/* FUNCTION execute:             */ 
/* This function receives a commend line argument list with the */ 
/* first one being a file name followed by its arguments. Then,  */ 
/* this function forks a child process to execute the command using */ 
/* system call execvp().            */ 
/* ----------------------------------------------------------------- */ 

void execute(char **argv) 
{ 
    pid_t pid; 
    int status; 

    if ((pid = fork()) < 0) {  /* fork a child process   */ 
      printf("*** ERROR: forking child process failed\n"); 
      exit(1); 
    } 
    else if (pid == 0) {   /* for the child process:   */ 
      if (execvp(*argv, argv) < 0) {  /* execute the command */ 
       printf("*** ERROR: exec failed\n"); 
       exit(1); 
      } 
    } 
    else {         /* for the parent:  */ 
      while (wait(&status) != pid)  /* wait for completion */ 
       ; 
    } 
} 

/* ----------------------------------------------------------------- */ 
/*     The main program starts here      */ 
/* ----------------------------------------------------------------- */ 

void main(void) 
{ 
    char line[1024];    /* the input line     */ 
    char *argv[64];    /* the command line argument  */ 

    while (1) {     /* repeat until done ....   */ 
      printf("Shell -> ");  /* display a prompt    */ 
      fgets(line,1024,stdin); /* read in the command line  */ 
      int i = strlen(line)-1; 
      if(line[ i ] == '\n') 
       line[i] = '\0'; 
      parse(line, argv);  /* parse the line    */ 
      if (strcmp(argv[0], "exit") == 0) /* is it an "exit"?  */ 
       exit(0);   /* exit if it is    */ 
      execute(argv);   /* otherwise, execute the command */ 
    } 
} 

output

+0

Как именно использовать fgets? Я верю, что нужно разбирать файл? – Amine

+0

Использование fgets() - очень плохая практика - она ​​не обеспечивает проверку границ, поэтому она открыта для серьезных ошибок безопасности - и большинство компаний не разрешают использовать какой-либо код, чтобы использовать код для проверки кода по этой причине. –

+0

@CharlesDuffy Я думаю, вы ошибаетесь. Поскольку scanf не имеет никакой проверки привязки. Вы можете использовать fgets как fgets (argv, 4, stdin). Второй аргумент проверяет границы. Теперь вы не можете ввести более 4 символов. –