Question
command interpreter/Shell Hi, I'm making a command interpreter/shell that need someone to implement part 2 of the homework requirement below in this code. Especially the
command interpreter/Shell
Hi, I'm making a command interpreter/shell that need someone to implement part 2 of the homework requirement below in this code. Especially the history command.
-----------------------------------------------------------------------------------------------------------------------------------
#include
#include
#include
#include
#include
#include
#include
/* The array below will hold the arguments: args[0] is the command. */
static char* args[512];
pid_t pid;
int command_pipe[2];
#define READ 0
#define WRITE 1
/*
* Handle commands separatly
* input: return value from previous command (useful for pipe file descriptor)
* first: 1 if first command in pipe-sequence (no input from previous pipe)
* last: 1 if last command in pipe-sequence (no input from previous pipe)
*
* EXAMPLE: If you type "ls | grep shell | wc" in your shell:
* fd1 = command(0, 1, 0), with args[0] = "ls"
* fd2 = command(fd1, 0, 0), with args[0] = "grep" and args[1] = "shell"
* fd3 = command(fd2, 0, 1), with args[0] = "wc"
*
* So if 'command' returns a file descriptor, the next 'command' has this
* descriptor as its 'input'.
*/
static int command(int input, int first, int last)
{
int pipettes[2];
/* Invoke pipe */
pipe( pipettes );
pid = fork();
/*
SCHEME:
STDIN --> O --> O --> O --> STDOUT
*/
if (pid == 0) {
if (first == 1 && last == 0 && input == 0) {
// First command
dup2( pipettes[WRITE], STDOUT_FILENO );
} else if (first == 0 && last == 0 && input != 0) {
// Middle command
dup2(input, STDIN_FILENO);
dup2(pipettes[WRITE], STDOUT_FILENO);
} else {
// Last command
dup2( input, STDIN_FILENO );
}
if (execvp( args[0], args) == -1)
_exit(EXIT_FAILURE); // If child fails
}
if (input != 0)
close(input);
// Nothing more needs to be written
close(pipettes[WRITE]);
// If it's the last command, nothing more needs to be read
if (last == 1)
close(pipettes[READ]);
return pipettes[READ];
}
/* Final cleanup, 'wait' for processes to terminate.
* n : Number of times 'command' was invoked.
*/
static void cleanup(int n)
{
int i;
for (i = 0; i < n; ++i)
wait(NULL);
}
static int run(char* cmd, int input, int first, int last);
static char line[1024];
static int n = 0; /* number of calls to 'command' */
int main()
{
printf("SIMPLE SHELL: Type 'exit' or send EOF to exit. ");
while (1) {
/* Print the command prompt */
printf("$> ");
fflush(NULL);
/* Read a command line */
if (!fgets(line, 1024, stdin))
return 0;
int input = 0;
int first = 1;
char* cmd = line;
char* next = strchr(cmd, '|'); /* Find first '|' */
while (next != NULL) {
/* 'next' points to '|' */
*next = '\0';
input = run(cmd, input, first, 0);
cmd = next + 1;
next = strchr(cmd, '|'); /* Find next '|' */
first = 0;
}
input = run(cmd, input, first, 1);
cleanup(n);
n = 0;
}
return 0;
}
static void split(char* cmd);
static int run(char* cmd, int input, int first, int last)
{
split(cmd);
if (args[0] != NULL) {
if (strcmp(args[0], "exit") == 0)
exit(0);
n += 1;
return command(input, first, last);
}
return 0;
}
static char* skipwhite(char* s)
{
while (isspace(*s)) ++s;
return s;
}
static void split(char* cmd)
{
cmd = skipwhite(cmd);
char* next = strchr(cmd, ' ');
int i = 0;
while(next != NULL) {
next[0] = '\0';
args[i] = cmd;
++i;
cmd = skipwhite(next + 1);
next = strchr(cmd, ' ');
}
if (cmd[0] != '\0') {
args[i] = cmd;
next = strchr(cmd, ' ');
next[0] = '\0';
++i;
}
args[i] = NULL;
}
-----------------------------------------------------------------------------------------------
Simple Shell Background In this project, you will implement a command line interpreter or shell in C language. The shell should operate in this basic way: when you type in a command (in response to its prompt), the shell creates a child process that executes the command you entered and then prompts for more user input when it has finished. The shell you implement will be similar to, but much simpler than, the one you run every day in Unix. You can find out which shell you are running by typing echo $SHELL at a prompt. You may then wish to look at the man pages for the shell you are running (most likely bash) to learn more about its functionalities. For this project, you need to implement only some as specified below.
Part 1: The Simple Shell 1. Your shell executable should be named mysh. Your shell source code should be in mysh.c, 2. The shell should run continuously, and display a prompt when waiting for input. The prompt should be EXACTLY '$'. No spaces, no extra characters. Example with a command: $/bin/ls -l 3. Your shell should read a line from stdin one at a time. This line should be parsed out into a command and all its arguments. In other words, tokenize it. o You may assume that the only supported delimiter is the whitespace character (ASCII character number 32). o You do not need to handle "special" characters. Do not worry about handling quotation marks, backslashes, and tab characters. This means your shell will be unable to support arguments with spaces in them. For example, your shell will not support file paths with spaces in them. o You may set a reasonable maximum on the number of command line arguments, but your shell should handle input lines of any length. 4. After parsing the command, your shell should execute it. A command can either be a reference to an executable OR a built-in shell command (see Part 2). For Part 1, just focus on running executables, and not on built-in commands. o Executing commands that are not shell built-ins and are just the executable name (and not a full path to the executable) is done by invoking fork() and then invoking exec(). o You may NOT use the system() function, as it just invokes the /bin/sh shell to do all the work.
Part 2: Implement Built-in Commands: exit, cd, history exit - Simply exits your shell after performing any necessary clean up. cd [dir] - Short for "change directory", and will be used to change the current working directory of your shell. Do not worry about implementing the command line options that the real cd command has in Bash. Just implement cd such that it takes a single command line parameter: The directory to change to. history [-c] [offset] - Similar to the Bash built-in history command, but much simpler. o history (without arguments) displays the last 100 commands the user ran, with an offset next to each command. The offset is the index of the command in the list, and valid values are 0 to 99, inclusive. 0 is the oldest command. Do not worry about persisting this list to a file; just store it in memory. Once more than 100 commands are executed, remove the oldest entry from the list to make room for the newer commands. Note that history is also a command itself and therefore should also appear in the list of commands. If the user ran invalid commands, those should also appear in the list. o history -c clears the entire history, removing all entries. For example, running history immediately after history -c should show history as the sole entry in the list. o history [offset] executes the command in history at the given offset. Print an error message of your choosing if the offset is not valid. o Example output for built-in history: o $cd /home/w4118 o $/bin/ls o my_file.txt o $history o 0 cd /home/w4118 o 1 /bin/ls o 2 history o $history 1 o my_file.txt o $history o 0 cd /home/w4118 o 1 /bin/ls o 2 history o 3 history 1 o 4 history o $history -c o $history o 0 history $
Part 3 is piping. the interpreter should be able to do multiple commands in one line using '|'
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started