mash banner

mash

4 devlogs
34h 44m 3s

Updated Project: I started this project about a year ago, but lost interest, because the architecture was pretty bad. It has never been submitted to hack-club though.
mash is a very simple shell. It has no terminal i. e. you have to rely on sys…

Updated Project: I started this project about a year ago, but lost interest, because the architecture was pretty bad. It has never been submitted to hack-club though.
mash is a very simple shell. It has no terminal i. e. you have to rely on system shell for that. As any good shell does it of course supports running other executables. There are also some of the classic builtins like cd, echo and exit. Then there is stdio redirection with pipes, etc… and we have history and aliasing.

This project uses AI

GitHub Copilot for Code completion and generating documentation + README (reviewed by me)

Demo Repository

Loading README...

Andraaal

Shipped this project!

Hours: 34.73
Cookies: 🍪 609
Multiplier: 17.54 cookies/hr

mash

I built a simple shell. You know the thing were you type commands and then magically something happens on your computer?
This is it. Here’s what I built in a little more detail:

Features

  • Executable execution: This is obviously a requirement for any shell and one of the core features of mash.
  • Basic Builtins: mash supports some of the most important (or simple) builtins. Here is a quick list
  • IO Interconnection (pipes, etc…): This was by far the most difficult feature to implement. Now though you can
    pipe stdin, out and err freely between any combination of builtin and external command.
  • Command Chronic: History is saved, can be viewed and executed. Also includes history persistence for good
    measure.
  • Advanced Aliasing: Not really that advanced, but you know… that was the best thing I could come up with for A.
    Anyways, mash supports creating and removing aliases for commands and aliases are resolved recursively to support
    using aliases within aliases, if you need that for whatever reason. Plus persistence between sessions to make them
    actually useful.

Storytime

I originally started this project about half a year ago at codecrafters.io. I finished the
core tasks no problem, but when I got to IO redirection my architecture started to fall apart (There wasn’t any notion
of expressions, it was just pure string manipulation). Then, when flavortown started, I finally convinced myself to
write a proper parser. In the end the parser wasn’t really much of a problem, as I had written one before. Finding a
data-structure that somehow combined Commands and Builtins proved to be much more difficult, because I didn’t do my
research.

First I followed some examples on how to redirect IO, but they only showed the convenient way if you have a
fixed pattern, which didn’t work if you wanted to create arbitrary connections between commands. Only after wasting a
bunch of time trying a lot of different strategies I realized you could also just create a new OS-pipe manually and use
that.

I just realized how long this has become and that I should stop ranting, but there is one more thing I wanted to talk
about: mash probably has more dead code than any of my other projects. I created a lot of infrastructure for future
expansions, which I ended up never creating. So in the unlikely case that anyone would like to add something like stdin
from a file that is really easy to do. You’re welcome.

End

Creating a shell was a neat experience and actually not that difficult once I got my overall design figured
out. But I suppose you could say that about anything: Once you figured it out, it became easy.

If anyone actually took the time to read all of this: Thank you! That means a lot to me. I hope you learned something
new or at least found it interesting to read. Cheers!

Andraaal

I did not expect to write another devlog for this project, because the code was finished. But, here we go again:

New Features

None

Bug Fixes

Also None

So what did I do?

I spent way too creating some GitHub Actions to automatically generate and publish the docs and to compile the binaries for people who don’t want to compile them themselves. It took hours and about 50 (FIFTY!!) commits (now squashed) of messing around with my workflow files to get something working. And the worst part is that you can’t test anything locally, you always have to push everything to GitHub and then wait until their server is done compiling everything, only to notice that the binaries overwrite each other or that you forgot to link glibc or something stupid.

Where did the absurd amount of hours come from?

I noticed that hackatime also tracked all the time I previously spent on this project and since I have never submitted it to Hackclub I thought why not include it here.

Attachment
0
Andraaal

I think this is it. My first complete project on flavortown! Yay!!
But before I go celebrate, here is what I did:

New Features

  • Aliases: Really the only new feature for mash in this devlog, as I focused mostly on fixing bugs and crashes and writing documentation. Anyways, you can now create and remove aliases with alias and unalias. I know you missed that `ll, at least I did.

Bug Fixes

I fixed a load of bugs, here are a few I can remember off the top of my head:

  • Fixed a crash when the user requested more history than was available.
  • Fixed a crash when mash syntax was at the end of the input
  • Some more I can’t remember right now…

Misc

  • I disabled all the dead code warnings from clippy, because I have way more infrastructure, than is actually used in any of my commands. Redirecting the stdin of a builtin is just nothing you do every day.
  • Many refactorings, expanding docs and writing a README with the help of AI

This is it - now I just have to figure out how I can create a web-demo to ship this project. Rust to WASM is great, but a shell in the web not so much…

Attachment
0
Andraaal

So… Devlog time!

New Features

  • History: At first I wanted to do this by hand, because I mean what else would you do? When I googled how to do that though the only things I found were a bunch of people on Reddit warning everyone. Apparently doing anything more than just reading is incredibly complicated, so I decided to follow their suggestions and use this library called rustyline. As it turns out using this library was kind of miserable too. The documentation is just rather .. sparse. To not say a bunch of one-liners and a half-hearted example. Still better than doing it by hand though, I guess. One major upside of using this library though, was that it has a lot of other features too, like …
  • Autocomplete: Yes, that’s only here because it came along with the library pretty much for free. Now mash supports completing Builtins, executables in PATH and files/directories.
  • Editing in the terminal: While I had to at least set up the autocomplete, the editing capabilities of rustyline are just there out of the box. After implementing the history I was very pleasantly surprised when I discovered this during testing.

Bug Fix

  • Builtin arguments could be overwritten they were written multiple times. Didn’t really matter, but still.

TODOs

  • Actually use stdin on some builtin after setting it all up
  • Fix the bug where it crashes at startup While taking the screenshots I realized scanning for executables in PATH is the problem. Probably just takes too long checking if some hundred files are executable and doing a syscall for each. I took it out for now.
  • Refactor some parts of the code
  • Maybe: Add aliases
    When looking at this list right know, I realized there is actually not much left. Maybe I can ship this soon?
Attachment
0
Andraaal

I finally managed to setup hackatime. It took me way too long to realise that I have to install the plugin AND run the setup script. In the process of figuring that out I then somehow broke my config file again. In short: It was a huge mess. Anyways, it’s up and running now.

Besides fighting with hackatime (mostly the wakatime plugin actually) I also made some changes to mash:

  • Pipes between external commands and builtins are now working correctly
  • Redirecting stdout/stderr to files is now possible too

The next thing I want to implement is history. Rewriting every command every time for testing is just getting way too tedious. This is probably also a good point to mention that this is my first devlog and first time in a hackclub event. I am super excited!

Attachment
0