I am writing my own Shell.

I am writing my own Shell.

Written by: Harto | 15.01.2025 | 7 min read
Harto Shell

During school I wrote my own shell using Go. I got the idea from the Codecrafters website. In December this course was free so I took the opportunity and began to write my own Shell. For all those who don't know Codecrafters, it is a webpage that gives you instructions what to do but not how to do. Then you commit your code and they run tests on it. If all tests pass you can do the next "task". With that you build your own shell quite fast and you can be sure that you have the fundamentals in your project.

After I finished almost all tasks I left the project for a bit to build this blog platform. Then all of a sudden December was finished and I couldn't access the Codecrafters course anymore. So that meant I am on my own now. Well not on my own but without the guidance of Codecrafters. But personally, I wanted to extend my Shell even more with more features and built-in commands. But first you need a good name...

Naming šŸ—‘

So for the first time in this blog I will say the name of the Shell. It is Totally Random and Aimless Shell of for short TRASh

You maybe think why this name? The reason for this name is obviously the acronym. And based on this acronym the name was born.

It also has this name because I want to add some random features just like a Trash wrapped. More about that later in the Features section.

http://s3.hartoms.ch/blog.harto.dev/uploads/67876eaeae9bf-trashlogo.png
Logo of TRAShell made by LordBuilder. Thank you

How it works āš’

  1. Take the Stdin (Standart Input of the user) and check if there is even a input. If this is the case and no errors occurred the user input will go to ...

  2. The parser takes the user input and resolves all of the escape characters. Then it splits the input in command standing for the application that gets called and a list named args standing for arguments. Those are the arguments and flags that will get passed into the command.

  3. The command and the arguments will then get passed in the command handler.

  4. The Command handler will first check if the command is a builtin command. If this is the caseĀ itĀ willĀ goĀ toĀ the Builtin Command Handler. There it will get passed to the correct script with the arguments. If this is not the case, it will check in the PATH variable for a application with the correct name. So you can easily install apps that will run from TRASh. If no command is found, it will return a not found.

  5. After that, the PS1 will get printed again. The PS1 is not the PlayStation 1 but the prompt string 1. This is the string that is printed before you can enter your prompt. In my shell I use a standard for that. First there will be the username and the hostname. After that you will get the current directory. After that you get a feature I quite like. You get the current Git Branch that is selected if a git repo is initialized.

This is the basic functionality of my Shell. But lets see into the future.

Future Ideas šŸš€

I have a load of ideas to improve my shell.

  1. First of all I would like to build way more builtins such as
    • help to get a list of all builtins
    • jobs to see all running jobs
    • fg to bring a job to the foreground
    • bg to bring a job to the background
    • kill to kill a job
    • alias to create shortcuts for commands
    • unalias to remove an alias
    • set to set shell options or variables
    • unset to unset a variable or option
    • rmdir to remove a directory
    • cp to copy files or directories
    • cat to display the contents of a file
    • head to display the first few lines of a file
    • tail to display the last few lines of a file
    • find to search for files and directories
    • basename to extract the filename from a path
    • dirname to extract the directory from a path
    • chmod to change file permissions
    • chown to change file ownership
    • and some more
  2. I would like to add a history feature. So you can see all the commands you have entered. This would work with a custom database I am writing. I will write a blog post about that in the future. This database would enable to store all commands and directories you have entered. Over a server you will be able to log in to you account and see and use you history from every device. You can obviously host this server yourself. Also will the data that will get transferred be encrypted and passwords will get filtered out by the shell.
  3. Then I would like to add some "trash" features that don't have a sense but are fun to use. For example:
    • TRASh Recap. Just like Spotify Wrapped or Twitch Recap you can see you Shell stats at the end of the year. This maybe include most used command and in what directory you where most often or at what time you entered the most commands. This data is gathered from your history. So that means it is also shared on multiple devices if you also sync your history. Obviously will this only be generated if you want to and will not be used by us in any other way.
    • TRASh Graph. I think the GitHub Graph is a thing most developers know. It is a graph where you can see hom much commits you made at a specific day. For a shell commits don't make much sense so it would be better to graph the amount of commands prompted or time spent in the shell. This data would also be synced if you want that so none of your data will be sent if you don't like it even though it is encrypted not even I can see that data.
      http://s3.hartoms.ch/blog.harto.dev/uploads/67876e1722ff6-Screenshot 2025-01-15 091244.png
      The GitHub Graph here from Theo.gg's account
    • and a lot more ideas. I think there are so many "TRASh features" ideas out there and there will be more, trust me.
  4. Also I want to add autocomplete because I can't use a shell without it.

Where do I stand? ā²ļø

Right now I am working at the database for the history feature and will implement some more builtins during that time. So I am quite busy with that. I will also write a blog post about the database and how it works. So stay tuned for that. On the GitHub repo you can see the progress of the shell. Some days ago I even made a release 0.1.0 where you can download the shells binary and use it. But be aware that it is not finished and there are some bugs in it. But I am working on it. If you want to use the current in dev version you can clone the repository and run go run main.go in the root of the project. This will start the shell and you can use it. If you want to build the binary you can run go build in the root of the project. This will create a binary that you can run with ./myshell. If you like this project you can give the repo a star ⭐. This would help me a lot. Here is the link to the GitHub repo

Thanks for reading this article

Harto