I have the following code:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <string.h> void passe(char *ligne, char **argv) { while (*ligne != '') { while (*ligne == ' ' || *ligne == 't' || *ligne == 'n') *ligne++ = ''; *argv++ = ligne; while (*ligne != '' && *ligne != ' ' && *ligne != 't' && *ligne != 'n') ligne++; } *argv = ''; } 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; }
The programme works fine, however when I parse something like “ps -f” it retunrs “execvp echouĂ©”, as the code removes the spaces. What should I exactly do to make it accept comands with options such as ps -f?
Advertisement
Answer
You should use fgets() instead of scanf(). Because fgets does not delete white spaces from your input. scanf function only consumes input until the whitespace. For example if you enter “ps -f” scanf consumes this input as “ps”. If you write ps directly to your shell terminal you can face with same exception that is what your programme exception. You can use fgets as stream reader that can be file stream or standard input stream(stdin). I have written code that solves your problem. You can check how you can use.
/* ----------------------------------------------------------------- */ /* 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 != '') { /* if not the end of line ....... */ while (*line == ' ' || *line == 't' || *line == 'n') *line++ = ''; /* replace white spaces with 0 */ *argv++ = line; /* save the argument position */ while (*line != '' && *line != ' ' && *line != 't' && *line != 'n') line++; /* skip the argument until ... */ } *argv = ''; /* 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 failedn"); exit(1); } else if (pid == 0) { /* for the child process: */ if (execvp(*argv, argv) < 0) { /* execute the command */ printf("*** ERROR: exec failedn"); 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] = ''; 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 */ } }