Micro Shell
2025-11-07
Project repositoryOverview
A simple, lightweight shell library with a completely static memory footprint. I developed this as part of NyxINS — a project exploring sensor fusion with consumer grade IMU components — which I ended up shelving after landing a job where I deal with similar topics on a daily basis. The shell itself is modular and useful enough to stand on its own, and I will likely reuse it in other projects.
It's completely platform agnostic, OS/non-OS, doesn't matter. It only requires you to provide implementation for two abstractions:
void shell_putc(const char c)
{
// Put single character to the interface
}
int shell_getc()
{
// Get single character from the interface
}
This allows you to define the shell on any interface you need, be it USB, UART or stdout/stdin on Linux. You define the commands like this:
shell_state_t state = device_shell_get_default_state(); // Get default config
shell_command_t commands[] = { // Define command array providing function pointers
{"foo", foo, "Foo command"}, // Command name, function pointer, help string
{"bar", bar, "Bar command"},
{"dead", dead, "Dead command"},
{"beef", beer, "Beed command"},
};
uint8_t num_commands = sizeof(commands) / sizeof(shell_command_t);
state.shell_commands = commands; // Assign the array and it's size
state.num_commands = num_commands;
And that's it, you just need to include the following in your main program loop:
device_shell_parse(&shell_state)
If initialized properly, you get an automatic help command. The shell also has a weakly defined function that gets called on the first clear of the buffers (at initialization). Because it's weakly defined you can override it with a custom implementation to print a banner on init, run whatever you need when the shell is created:
void shell_greeting_hook()
{
const char* banner[] = {
"╔════════════╗\n",
"║ BANNER ║\n",
"╚════════════╝\n"
};
for(int i=0; i<sizeof(banner) / sizeof(banner[0]); i++)
{
shell_puts(banner[i]);
}
}
Here is the shell running on my Linux machine from a test binary, the interface is just set to stdout/stdin.
Worth noting is this shell is not thread safe and using it from multiple threads will lead to race conditions.