A COMP-354 Course project. This is a simple implementation of a POSIX compatible shell written in C++.
- cmake
- A POSIX compliant environment
- C++20+ compiler
# create build output directory
cmake -B ./build
# build project. The compiled executable will be placed in ./build/nish
cmake --build ./build-
Bash-like command line parsing
- Quotes
'and":"arg1 arg2"is considered one argument - Escaping:
"I want a double-quote in this string: \""
- Quotes
-
Environment variables:
- Setting a variable:
$ set VAR1 value1 - Exporting a variable to child processes:
$ export VAR1 - Variable substitution:
$ echo Hello ${VAR1}will printHello value1 - View all current variables with the
envcommand
- Setting a variable:
-
Output redirection to file:
$ echo 'Hello there' > ./output.txt$ ls -la > ../output.txt
-
Path resolution for executables via
$PATHvariable$ ping ...will search directories in$PATHfor thepingexecutable$PATHtakes on the format of:/dir1:/dir2:/dir3- To add a dir to the path:
$ set PATH ${PATH}:/newdir
- Job back-grounding
- Input file redirection
- Command piping
- Batch file processing
Built-in command implementations are designed to be modular making it easy to integrate a new
built-in. This is facilitated via a global handler registry (see implementation under the Registry/ directory).
Adding a new built-in is simple:
- Create a new class which inherits from
BaseCmdHandlerin theHandlers/directory - Implement the
run(string prog, vector<string> args)function - Register the built-in with a specific command with
REGISTER_HANDLER(command, DerivedClass) - Add the .cpp file to
Handlers/CMakeLists.txt
Example:
#include <string>
#include <vector>
#include "BaseCmdHandler.hpp"
using std::string, std:;vector;
class ExampleHandler : public BaseCmdHandler {
int run(const string& prog ,const vector<string>& args) override {
// `prog` specifies via which command this handler was triggered with,
// useful in the case where a handler is registered under different commands
// or for the default handler (see Handlers/Default.[hpp|cpp])
// `args` is the vector of arguments parsed after the command, after
// environment variable substitution
printf("Example handler triggered!\n");
// the return value of this function is used as the status code
return 0;
}
}
// register the handler with the Registry
REGISTER_HANDLER("example", ExampleHandler);
// now the handler will be used when the command line starts with "example":
// nish (...) [...] $ example arg1 arg2
// Example handler triggered!