go-shell is a simple command-line shell built with Go that allows developers and enthusiasts to explore and execute built-in and external commands efficiently.
- Built-in commands like
exit
,echo
,pwd
,cd
,ls
, andtype
. - Supports execution of external commands available in the
PATH
. - Simple and intuitive interface.
- Lightweight and fast, leveraging Go's concurrency model.
- Go 1.22 or higher
- Git
Installing go-shell is as simple as cloning the repository and running the build command!
git clone https://github.com/sanurb/go-shell
cd go-shell
go build -o go-shell main.go
USAGE:
go-shell
Example:
go-shell
$ echo Hello, World!
Hello, World!
Planning to add more advanced features and improvements.
- Setup repo
- Implement basic built-in commands
- Support external command execution
- Add support for piping and redirection
- Enhance error handling and user feedback
- Write comprehensive tests
go-shell was inspired by the desire to deeply understand how command-line shells work and to provide a tool that developers can use and extend. As Richard Feynman said, “What I cannot create, I do not understand”. This project embodies the philosophy that real understanding comes from building and creating.
- Challenges: Ensuring compatibility with various external commands and handling different edge cases in command execution.
- Learnings: Deepened understanding of Go's
os/exec
package, process management, application of some design patterns like factory pattern using go
Design Decisions for Enhanced Clarity and Extensibility
The diagram showcases a refined class structure for our interactive shell. Key decisions were made to improve code organization and maintainability:
-
Command
Interface: This establishes a contract for all commands, ensuring consistent behavior and enabling seamless addition of new commands in the future. -
BaseCommand
Class: This provides default implementations for commonCommand
methods, reducing boilerplate code in concrete command classes. -
BuiltinCommand
andExternalCommand
: These abstract classes categorize commands based on their origin (internal to the shell or external system commands), enhancing clarity and separation of concerns. -
LsCommand
Specialization:LsCommand
is further specialized due to its unique handling of options and arguments, showcasing the flexibility of theCommand
pattern to accommodate varying command behaviors. -
CompositeCommand
for Complex Operations: This class enables the execution of multiple commands as a single unit, promoting modularity and reusability. -
CommandFactory
for Instantiation: This class decouples command creation from the rest of the system, allowing for easy extension and modification of command types. -
CommandParser
for Interpretation: This class parses user input and delegates command creation to theCommandFactory
, promoting a clean separation of responsibilities.
This structure facilitates future enhancements, such as the integration of new command types or the implementation of additional features.
classDiagram
class Command {
<<interface>>
Execute() error
SetStdin(io.Reader)
SetStdout(io.Writer)
StdinPipe() (io.WriteCloser, error)
StdoutPipe() (io.ReadCloser, error)
}
class BaseCommand {
Stdin io.Reader
Stdout io.Writer
SetStdin(io.Reader)
SetStdout(io.Writer)
StdinPipe() (io.WriteCloser, error)
StdoutPipe() (io.ReadCloser, error)
}
class BuiltinCommand {
<<abstract>>
}
class LsCommand {
Options LsOptions
DirPath string
SetArgs([]string)
listDirectory() error
printLongFormat(fs.DirEntry)
}
class OtherBuiltinCommand {
<<abstract>>
}
class ExternalCommand {
<<abstract>>
}
class CompositeCommand {
commands []Command
Add(Command)
Execute() error
SetStdin(io.Reader)
SetStdout(io.Writer)
StdinPipe() (io.WriteCloser, error)
StdoutPipe() (io.ReadCloser, error)
}
class CommandFactory {
commands map[string]func([]string, io.Writer) Command
Create(string, []string) (Command, error)
Register(string, func([]string, io.Writer) Command)
}
class CommandParser {
factory CommandFactory
Parse(string) (Command, error)
}
class Shell {
parser CommandParser
Run()
}
Command <|-- BaseCommand
BaseCommand <|-- BuiltinCommand
BuiltinCommand <|-- LsCommand
BuiltinCommand <|-- OtherBuiltinCommand
BaseCommand <|-- ExternalCommand
Command <|-- CompositeCommand
CommandFactory o-- Command
CommandParser o-- CommandFactory
Shell o-- CommandParser
note for LsCommand "Handles specific options and arguments"
note for OtherBuiltinCommand "Examples: CdCommand, EchoCommand, etc."
note for ExternalCommand "Examples: Operating system commands"
- Build your own Shell - codecrafters.io
- Coding Challenges FYI
- Coding a Shell using C
- Writing a simple shell in Go
⭐ hit the star button if you found this useful ⭐