0% found this document useful (0 votes)
73 views

Ilustración 1 Executing The Program

This document describes a C program that implements a UNIX shell with command history functionality. The shell accepts commands from the user, executes each in a separate process, and stores the last 10 commands in a history. The user can view the history with Ctrl-C and rerun previous commands by entering "r" followed by a command letter or number. Any errors in rerunning commands from history will not add the command to the history.

Uploaded by

Omar Muñoz
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
73 views

Ilustración 1 Executing The Program

This document describes a C program that implements a UNIX shell with command history functionality. The shell accepts commands from the user, executes each in a separate process, and stores the last 10 commands in a history. The user can view the history with Ctrl-C and rerun previous commands by entering "r" followed by a command letter or number. Any errors in rerunning commands from history will not add the command to the history.

Uploaded by

Omar Muñoz
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 11

Project-UNIX Shell and History Feature This project consists of modifying a C program which serves as a shell interface that

accepts user commands and then executes each command in a separate process. A shell interface provides the user a prompt after which the next command is entered.

Ilustracin 1 Executing the program

Ilustracin 2 Executing gedit command, waits for the child process to terminate

UNIX shells typically also allow the child process to run in the background-or concurrentyl-as well by specifying the ampesand (&) at the end of the command. Example:

Ilustracin 3 Executing gedit command, running parallel background

This program is terminated when the user enters <Control><D> and setup() theb invokes exit(). The contents of the command entered by the user is loaded into the args array.

Ilustracin 4 Executing commands with different parameters

Creating a History Feature This code also provides a history feature that allows the user access up to the 10 most recently entered commands. These commands will be numbered starting at 1 and will continue to grow larger even past 10, e.g. if the user has entered 35 commands, the 10 most recent commands sholud be numbered 26 to 35. The user will be able to list these commands when he/she presses <Control><C>, which is the SIGINT signal. When the user presses that command, the signal handler will output a list of the most recent 10 commands.

Ilustracin 5 Pressing CTR + C to show the command history

Ilustracin 6 Executing echoes

Ilustracin 7 The history is updated. Only 10 commands are stored

With the list, the user can run any of the previous 10 commands by entering r x where 'x' is the first letter of that command. If more than one command starts with 'x', execute the most recent one.

Ilustracin 8 Executing "r e", searching the last command with initial the letter e

Ilustracin 9 Executing "r l", searching the last command with initial letter 'l'

Also, the user should be able to run the most recent command again by just entering 'r'. Any command that is executed in this fashion will be echoed on the user's screen and the command is also placed in the history buffer as the next command.

Ilustracin 10 Executing "r", executing the last command used

Ilustracin 11 History is updated whe 'r' is executed and adds the command executed

If he user attempts to use this history facility to run a command and the command is detected to be erroneous, an error message should be given to the user and the command not entered in the history list, and the execvp() will not be called

Ilustracin 12 Control of errors in the history

Cdigo del proyecto


#include #include #include #include #include #include #include #include <stdio.h> <signal.h> <unistd.h> <stdlib.h> <errno.h> <sys/types.h> <string.h> <ctype.h> 10 /* size of history */ 80 50

#define MAX_COMMANDS #define MAX_LINE #define BUFFER_SIZE

char history[MAX_COMMANDS][MAX_LINE]; char display_history[MAX_COMMANDS][MAX_LINE]; static char buffer[BUFFER_SIZE]; int ctrC = 0; int command_count = 0; void addtohistory(char inputBuffer[]) { int i = 0; int limit_history = 0; if (command_count >= 9) { limit_history = 9; } else { limit_history = command_count; } //shift all other commands in history[] if (command_count > 0) { for (i = limit_history; i > 0; i--) { /** * quitar este comentario para ver como va recorriendo los comandos printf("Copia [%d] %s a [%d] %s\n", i - 1, display_history[i - 1], i, display_history[i]); */ strcpy(history[i], history[i - 1]); strcpy(display_history[i], display_history[i - 1]); } } // add the command to beggining strcpy(history[0], inputBuffer); // add the display-style command to beginning history i = 0; while (inputBuffer[i] != '\n' && inputBuffer[i] != '\0') { display_history[0][i] = inputBuffer[i]; i++; } display_history[0][i] = '\0'; //make a C string

++command_count; return; } /* the signal handler function */ void handle_SIGINT() { int i, upper; //write(STDOUT_FILENO,buffer,strlen(buffer)); if (command_count < MAX_COMMANDS){ upper = command_count; } else { upper = MAX_COMMANDS; } //Desplegar 10 comandos recientes en pantalla printf("\n---Command History---\n"); for (i = 0; i < upper; i++) { printf("%d \t %s\n", command_count - i, display_history[i]); } ctrC = 1; //exit(0); } /** setup() reads in the next command line, separating it into distinct tokens using whitespace as delimiters. setup() modifies the args parameter so that it holds pointers to the null-terminated strings that are the tokens in the most recent user command line as well as a NULL pointer, indicating the end of the argument list, which comes after the string pointers that have been assigned to args. */ void setup(char inputBuffer[], char *args[], int *background) { int length; /* # of characters in the command line */ int i; /* loop index for accessing inputBuffer array */ int start; /* index where beginning of next command parameter is */ int ct; /* index of where to place the next parameter into args[] */ char command_firstl; /* first letter of command */ ct = 0; /* read what the user enters on the command line */ length = read(STDIN_FILENO, inputBuffer, MAX_LINE); //printf("First size: %zu\n",strlen(inputBuffer));//QUITAR //printf("length: %d\n",length); start = -1; if(length == 0) exit(0); /* ^d was entered, end of user command stream */ if(length < 0){ //perror("error reading the command"); //exit(-1); /* terminate with error code of -1 */ } /* flag so it doesn't add command to history */ /* exits program */

/** * Check if they are using history */ if (inputBuffer[0] == 'r') { //printf("\nI received R\n"); if (command_count == 0) { printf("No history\n"); //return 1; } else if (inputBuffer[1] == '\n') { // restore the previous command int index = 0; strcpy(inputBuffer, history[index]); //echoes command on screen printf("COMMAND -> %s\n", display_history[0]); length = strlen(inputBuffer) + 1; } else if (inputBuffer[1] == ' ') { /* checks for r followed by a letter */ if (isalpha(inputBuffer[2])) { /* If is letter (alphabetic) */ int i = 0; for (i = 0; i < 10; i++) { command_firstl = history[i][0]; /* extract first letter of command in history */ if (command_firstl == inputBuffer[2]) { strcpy(inputBuffer, history[i]); //echoes command on screen printf("COMMAND -> %s\n", display_history[i]); length = strlen(inputBuffer) + 1; break; } } if (i >= 10) { /* didn't match any beggining letter */ strcpy(inputBuffer, "echo No hay comandos que comiencen con esa letra\n"); length = strlen(inputBuffer) + 1; ctrC = 1; /* don't add to history */ } } else { printf("Error, ingrese la primera letra del comando\n"); } } else { printf("Error, deje un espacio entre letras\n"); } } ctrC ? ctrC = 0 : addtohistory(inputBuffer); /* examine every character in the inputBuffer */ for(i = 0; i < length; i++){ switch(inputBuffer[i]){ case ' ': case '\t': /* argument separators */ if(start != -1){

/* set up pointer at beggining of command or command option */ args[ct] = &inputBuffer[start]; ct++; /* increase counter */ } inputBuffer[i] = '\0'; /* add a null char; make a C string*/ start = -1; break; case '\n': */ if(start != -1){ args[ct] = &inputBuffer[start]; ct++; } inputBuffer[i] = '\0'; args[ct] = NULL; /* no more arguments to this command */ break; default : /* some other character */ if(start == -1) start = i; if(inputBuffer[i] == '&'){ *background = 1; inputBuffer[i] = '\0'; } } } args[ct] = NULL; /* just in case the input line was > 80*/ } int main(void) { char inputBuffer[MAX_LINE]; /* buffer to hold command entered */ int background; /* equals 1 if a command is followed by '&' */ char *args[MAX_LINE/1]; /* command line (of 80) has max of 40 arguments */ /*code made by CREW ISD*/ int ppid,pid; /*code made by CREW ISD*/ /* set up the signal handler */ struct sigaction handler; handler.sa_handler = handle_SIGINT; handler.sa_flags = 0; sigemptyset(&handler.sa_mask); sigaction(SIGINT, &handler, NULL); strcpy(buffer,"Caught <ctrl><c>\n"); while(1){ background = 0; ppid = getpid(); //printf("Parent: %d\n",ppid); printf("COMMAND -> "); /* should be the final char examined

fflush(stdout); /* setup() calls exit() when Control-D is entered */ setup(inputBuffer, args, &background); /** code made by CREW ISD */ pid = fork(); if(pid == 0){ execvp(args[0],args); if (inputBuffer[0] != 'r') { vlido printf("Error: Unknown command, please try again\n"); exit(-1); } } else { if(background == 0){ //wait(NULL); //printf("\nWaiting for the child: %d to terminate",pid); wait(NULL); //printf("\nEND WAITING\n"); //printf("Child: %d\n",pid); }else{ //exit(0); printf("\nbackg = 1, running child: %d in parallel with parent: %d\n", pid, ppid); //printf("Printing contents: %c\n",*args[0]); } } /** code made by CREW ISD */ /* printf(args[0]); printf(args[1]); printf("%d\n",background); */ /** the steps are: (1) fork a child process using fork() (2) the child process will invoke execvp() (3) if background == 1, the parent will wait, otherwise it will invoke the setup() function again. */ } }

//Child process //No imprime error pues r es

You might also like