Very Basic C Shell Linux Command Line Interpreter
- a basic multi-process C shell Linux command interpreter
- in the future, it may be expanded to take a traveling
salesman threads, with a sorter of their paths
- goals of implementation were to become more familiar with the primitives used in process control and inter-process communication
- future goals may be to simulate a multi-threaded
environment that implements inter-process communication,
signal handling, and a stronger understanding of flow
control
Two primary aspects of this project:
- implementing a shell environment to process command
line input specification and execution of a parallel
program that is either comprised of multiple processes
or threads
- Concepts Used to complete this project included:
inter-process communication, (including pipes, signals
, shared memory), process creation and execution.
- Relevant functions include:
getcontext, makecontext, setcontext, swapcontext,
sigsetjump, siglongjump, kill, pipe, popen, shmget,
shmctl, shmat, fork, execve, execvp, etc.
Four Programs Involved
Only the first very basic version of the shell is done and the rest are future work:
- Basic shell (done in C) for specifying and
executing programs, called "myshell" .
- Goal: to implement a basic shell called "myshell",
to learn how a command interpreter works. It's a
simple parser to interpret commands, that uses
fork/exec functions to create and execute these
commands. I/O redirection and the use of pipes was
required.
- "Myshell" specification: similar to the "bash"
shell, with the following requirements:
- Execution file: the execution file called
"myshell".
- Shell prompt: If the input to the "myshell"
program is from a terminal, you should print
"myshell>" as the prompt for the user to type in
the shell command. If the input is from a file,
you should not print any prompt, as this will help
when it comes to testing your projects. NOTE: You
can use the "isatty" function to determine whether
the input (via a specific file descriptor) is from
a terminal or not.
- Command execution and shell termination:
"myshell" reads its input from stdin, parsing the
command line to determine how to execute the shell
request. Termination of "myshell" occurs either
when a user types ctrl-d, or when the
program issues an "exit()" call due to some
error/termination condition.
Description of the valid command lineformats.
- "Cmd"--A single command that identifies the
name of a program file.
- "cmd; cmd"--A sequence of commands: "myshell"
should execute them one after another.
- "cmd \> output_file"--Redirect stdout of the cmd
to the file with the name "output_file".
- "cmd \< input_file"--Redirect stdin of the cmd
to the file with the name "input_file".
- "cmd 1> output_fil"e--Redirect stdout of the cmd
to the file with the name "output_file".
- "cmd 2> output_file" - Redirect stderr of the
cmd to the file with the name "output_file".
- "cmd &> output_file" - Redirect both stdout and
stderr of the cmd to the file with the name
"output_file".
- "cmd1 | cmd2 | cmd3" - Pipeline the output of
the command before each "|" symbol to the input
of the command after the same "|" symbol.
- "cmd &" - "myshell" should let cmd execute in
the background, so that the shell can interpret
further input commands.
Testing It:
At Linux prompt, type gdb myshell , which starts
the gdb debugger. It works for some but not all of
the specified cases.
Test cases that I tried before setting project
aside for now:
- Test: Shell will list all files in directory.
- Command: ls
- Test: Shell will first list all files in
directory. Then it will list information
about the active processes running.
- Command: ls;ps
- Test: Shell will do a directory listing
and send it to the output file "lsOutputFile".
- Command: ls > lsOutputFile
- Test: Shell will do a directory listing
and pipe this output list of directory files
to be the input to the second command
running as a process in the shell, grep,
which will then output only the files that
match the string passed as input to grep's
command, "lsOut", and send this list of
files to the standard out console output.
- Command: ls | grep lsOut
- How I Run and Test it: run gdb with the
myshell binary, and after running it, type
the test cases in the test case file at the
shell prompt and then view the output. In
the case you send the output to an output
file, after the command is done, you must do
the command "more outputFileName.txt" to
view the output from the previous command
you ran.
Special Input:
- ctrl-c is the default key sequence to send a
"SIGINT" signal to a process.
- In "myshell", you should intercept this signal,
and send it to all "foreground" processes to stop
them instead of stopping "myshell".
Prevent "zombie" children:
- when a command running in the background
finishes, it must inform the "myshell" (parent)
process via a "SIGCHLD" signal.
- "myshell" can then keep track of which child
processes are still active.
Basic Shell operation:
- You should use the "fork" syscall to create each
child of "myshell" and then one of the "exec*"
functions to execute the command in the
corresponding child's address space.
- You should also use either the "wait" or
"waitpid" function to determine the exit status of
a terminating child.
- For output redirection and piping between
processes: to redirect a file descriptor to stdin,
stdout, or stderr you can use the "dup2"
function.