= TB shell scripting for MOP2 Kamil Kowalczyk 2025-11-08 :jbake-type: post :jbake-tags: MOP2 osdev :jbake-status: published This post is about TB (ToolBox) - the shell interpreter for MOP2 operating system. = Invoking applications 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). .Example of listing currently running processes [source] ---- 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 ;). .Example of calling an application via an alias [source] ---- $pctl ls ---- Now that's way better! === Creating new aliases To create an alias we can type [source] ---- 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. [source] ---- 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 MP:/path/`. == Logging 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: [source] ---- setlogcmds yes ---- Now the user will see printed statements, for eg. during the system start up: [source] ---- 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 ---- == String stack and subshells 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: [source] ---- # 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 ` 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: [source] ---- stackpush 'hello world string!' print $stack stackpop ---- === The `do` function The `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: [source] ---- 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 ;).