base:/bin/pctl ls
08 November 2025
This post is about TB (ToolBox) - the shell interpreter for MOP2 operating system.
Applications are invoked by providing an absolute path to the binary executable and the list of
arguments. In MOP2 paths must be formatted as MOUNTPOINT:/path/to/my/file. All paths are absolute
and MOP2 doesn’t support relative paths (there’s no concept of a CWD or current working directory).
base:/bin/pctl ls
Typing out the entire path might get tiresome. Imagine typing MOUNTPOINT:/path/to/app arg more args
every time you want to call an app. This is what TB aliases/macros are for. They make the user type
less ;).
$pctl ls
Now that’s way better!
To create an alias we can type
mkalias pctl base:/bin/pctl
And then we can use our $pctl!
But there’s another issue - we have to write aliases for every application, which isn’t better than
us typing out the entire path. Luckliy, there’s a solution for this. TB has two useful functions
that can help us solve this - eachfile and mkaliasbn.
eachfile takes a directory, an ignore list and a command, which is run for every entry in the said
directory. We can also access the current directory entry via special symbol called &EF-ELEM.
In base/scripts/rc.tb we can see the full example in action.
eachfile !.gitkeep base:/bin \
mkaliasbn &EF-ELEM
This script means: for each file in base:/bin (excluding .gitkeep), call mkaliasbn for the current
entry. mkaliasbn then takes the base name of a path, which is expanded by &EF-ELEM and creates
an alias. mkaliasbn just simply does mkalias <app> MP:/path/<app>.
In the UNIX shell there’s one very useful statement - set -x. set -x tells the shell to print out
executed commands. It’s useful for script debugging or in general to know what the script does (or
if it’s doing anything / not stuck). This is one thing that I hate about Windows - it shows up a
stupid dotted spinner and doesn’t tell you what it’s doing and you start wondering. Is it stuck?
Is it waiting for a drive/network/other I/O? Is it bugged? Can I turn of my PC? Will it break if I
do? The user SHOULD NOT have these kinds of questions. That’s why I believe that set -x is very
important.
I wanted to have something similar in TB, so I’ve added a setlogcmds function. It takes yes or
no as an argument to enable/disable logging. It can be invoked like so:
setlogcmds yes
Now the user will see printed statements, for eg. during the system start up:
this is an init script!
+$tb -m runfile -f base:/scripts/mount.tb
Mounting filesystems...
+$fs mount -mp uhome -fs LittleFS -dev atasd-ch0-M-part2 -fmt no
OK uhome
In UNIX shell, it’s common to get the output of an application, store it into a variable and then pass that variable around to other apps. For eg:
# Use of a subshell
MYVAR=$(cat file.txt)
echo $MYVAR | myapp # or something...
In TB, I’ve decided to go with a stack, since I find it easier to implement than a variable hashmap. A stack can be implemented using any dynamic list BTW.
The stack in TB is manipulated via stackpush and stackpop functions. We can stackpush a string
using stackpush <my string> and then stackpop it to remove it. We can also access the top of
the stack via $stack. It’s a special magic alias, which expands to the string that is at the top.
An example of stack usage would be:
stackpush 'hello world string!'
print $stack
stackpop
do functionThe do function does what a subshell does in UNIX shell. We can do a command an then have it’s
output placed at the top of the stack. An example of this would be:
do print 'hello world from subshell'
print $stack
stackpop
It’s a simpler, more primitive mechanism than the UNIX subshells, but it gets the job done ;).