{"componentChunkName":"component---src-templates-md-page-js","path":"/proj_shell/","result":{"data":{"markdownRemark":{"rawMarkdownBody":"\nIn this project you will implement a simple shell program that supports\nI/O redirection and pipelines. The goal of this\nproject is for you to learn about the `fork`, `execvp`, and `waitpid`\nsystem calls, as well as I/O redirection.\n\n## Commands\nYour shell will read commands from its standard input and execute them.\nEach command consists of one or more *words* separated by white space\n(spaces or tabs).\nThe first word specifies a program to run. The shell invokes this program\nas a child process and all passes of the words (including the program name)\nto it as arguments.\nFor example, consider this command:\n```\nfind . -name shell.cc\n```\nIt has four words: `find`, `.`, `-name`, and `shell.c`. The first word,\n`find`, is the name of the program to run.\n\n## I/O Redirection\nNormally, the shell's child processes use the same standard input and\nstandard output files as the shell.\nHowever, the characters `<` and `>` can be used to change the standard\ninput and/or output of a command.\nFor example, the command\n```\ngrep std::string shell.cc > lines\n```\nwill write all of the lines of the file `shell.cc` that contain the\nstring `std::string`\nto the file `lines` instead of the terminal, and the command\n```\nwc < shell.cc\n```\nwill read `shell.cc` and output statistics such as the number of lines.\nThe characters `<` and `>` can appear anywhere in a command; they\nterminate the current word, if any, and the next word is taken as\nthe name of the file.\nThe redirection information is not included in the arguments passed to\nthe command.\nFor example, consider the following command:\n```\ngrep<shell.cc>match.txt -H\n```\nThe `grep` command will receive two arguments, `grep` and `-H`; its\nstandard input will come from the file `shell.cc` and its output\nwill be written to the file `match.txt`.\n\n## Pipelines\nIf the character `|` appears in a command line, it ends one command\nand starts another; the standard output of the first command will be\npassed as input to the second command using a pipe.\nThis is called a *pipeline*.\nFor example,\n```\ngrep std::string shell.cc | wc\n```\nwill arrange for the lines of `shell.cc` containing the string\n`std::string` to be passed as standard input to `wc`, where they\nwill be counted. It has the same effect as the following\ncommands\n```\ngrep std::string shell.cc > tmp\nwc < tmp\nrm tmp\n```\nHowever, in the pipeline case the `grep` and `wc` commands will run\nconcurrently, so they can potentially finish more quickly.\nIf a pipeline also includes I/O redirection, `<` and `>` apply to\ntheir respective commands in the pipeline and redirections take\npriority over pipes (see Other Requirements for details).\n\n## Implementation\nFor this project you will need to use the following system calls:\n\n* `fork`: creates a new process, which is a duplicate of the parent\n* `execvp`: after a new child process has been forked, invoke this\n  in the child to start a new program in that process. This kernel\n  call uses the PATH environment variable to find the executable file\n  corresponding to a command; this provides easy access to the standard\n  system programs.\n* `waitpid`: after creating one or more child processes, use this\n  system call to wait for each child to exit. If you prefer, you may\n  use the `wait` kernel call, which waits for *any* child to exit, rather\n  than waiting for a specific child.\n* `open`: open a file that is going to be used for I/O redirection\n* `pipe`: creates a new pipe for pipelines\n* `dup2`: once you have opened a file or pipe, this can be used to make\n  a copy of its file decscriptor in descriptor 0 (for standard input\n  or 1 (for standard output) for a child process\n* `close`: to close files and pipes when they are no longer needed\n\nYou can learn more about these system calls with the `man` program.\nFor example,\n```\nman execvp\n```\nwill print information about the `execvp` system call.\n\n## Development and Testing\nDo your work for this project on the Myth cluster. To get started,\ninvoke the following command:\n```\ngit clone @gitRepo@/shell.git cs111_p1\n```\nThis will create a new directory `cs111_p1`. Do your work for the\nproject in this directory. You can use Git to manage your revisions\nto the project.\n\nThe directory will contain a skeleton\nfile `sh111.cc` in which we have provided code to parse command lines.\nThe parser creates one `cmd` struct describing each suprocess that must be\ninvoked;\neach `cmd` contains the words that must be passed to that command, plus\nzero or more `redirect` structs that describe I/O redirection for that\ncommand. See the code for detailed documentation of these structures.\nOnce a command line has been parsed, the function `run_pipeline` will be\ninvoked to create the child processes and wait for them to complete.\nYou must implement the body of this function, creating children as\ndescribed by the argument to `run_pipeline`. If more than one command\nis specified, you must create pipes between consecutive commands in\nthe pipeline.\n\nThe directory will also contain a `Makefile`. If you type `make`,\nit will compile `sh111.cc`, creating an executable file `sh111`.\nYou can run your shell by typing the following command:\n```\n./sh111\n```\nA prompt should appear\nand you should be able to invoke shell commands. Most simple\nshell commands should work just as well in `sh111` as in your normal\nshell. However, a few commands, such as `cd` and `exit`, won't work\nin `sh111`. These are *built-in* commands: normal shells such as\n`bash` execute them directly, without invoking a child process.\nCommands like `cd` need to be\nbuilt-in because executing them in a child process won't be useful.\nFor example, if a child process changes its working directory, that\nwon't have any effect on the shell or on future commands it invokes,\nand if a child process exits, that won't cause the parent shell to\nexit. `sh111` doesn't support built-in commands, so these commands\nwon't work.\n\nYou can run a series of basic tests on your shell\nby invoking the command `./run_tests`. It will print error\nmessages if tests fail; you should then be able to go back and run\nthe failing tests manually (each is just a series of shell commands)\nto debug the problem.\nWe do not guarantee that these tests are exhaustive, so passing\nall of the tests is not necessarily sufficient to ensure a perfect\nscore (CAs may discover other problems in reading through your code).\n\n## Order of Implementation\nWe recommend implementing the project in stages, so that you can\nsee simple things working before trying more complex things.\nHere is one possible order:\n\n* When `run_pipeline` is invoked, ignore its argument. Just `fork` a\n  child and have the child print a message and then exit immediately,\n  without invoking `execvp`. The parent waits for the child to exit.\n* Get a single command to run in the child process and wait on it.\n  This should allow commands like `ls -l` and `sleep 5` to run just\n  as they would in any standard shell.\n* Get two commands in a pipeline to run simultaneously in two separate\n  child processes, with the first piping its output to the second.\n  This means the command `ls | wc -l` will run and print out the total\n  number of files in your current directory.\n* Get an arbitrary number of commands in a pipeline to run simultaneously,\n  each in its own distinct child process. This means the command\n  `ls | grep sh111 | wc -l` will print out the number of files in the\n  current directory that contain the substring \"sh111\". This task is\n  probably the most difficult, so work carefully!\n* Finally, incorporate file redirection into each of the commands.\n\n## Other Requirements\n* You must use pipes to pass data between processes in a pipeline (for\n  example, it is not OK to run the processes one at a time, redirecting\n  one process's output to a file and then redirecting the next process's\n  input from the same file). This allows all of the processes in the\n  pipeline to run concurrently.\n* If I/O redirection is also specified for a command in a pipeline, redirection\n  takes priority over pipes. For example, consider the following command:\n  ```\n  grep std::string shell.cc > grep.out | wc\n  ```\n  The I/O redirection will cause `grep`'s output to go to the file `grep.out`\n  instead of the pipe connecting to `wc`. The pipe will still exist, and\n  `wc` will read from it, but the writing end of the pipe will have been\n  closed, so `wc` will immediately read an end-of-file condition.\n  (If the redirection were specified after the pipe symbol, it would have\n  applied to `wc` instead of `grep`)\n* You must ensure that each child process starts with only three open\n  file descriptors: standard input, standard output, and standard error.\n  If you have opened any other descriptors for files or pipes, you must\n  close them before `exec`ing the child.\n\n## Submitting Your Work\nTo submit your solutions, `cd` to the directory containing your\nwork, then invoke the command\n```\n./submit\n```\nIf you discover problems or improvements after you have submitted,\nyou may resubmit; only the latest submit will be graded.\n","frontmatter":{"title":"Project 1: A Simple Shell"}}},"pageContext":{"slug":"/proj_shell/"}},"staticQueryHashes":[]}