Compare commits
2 Commits
01626432c4
...
34be439843
| Author | SHA1 | Date | |
|---|---|---|---|
| 34be439843 | |||
| 0f7959a642 |
Binary file not shown.
|
Before Width: | Height: | Size: 121 KiB |
131
content/blog/MOP2/tb-shell-scripting.adoc
Normal file
131
content/blog/MOP2/tb-shell-scripting.adoc
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
= 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 <app> MP:/path/<app>`.
|
||||||
|
|
||||||
|
== 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 <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:
|
||||||
|
|
||||||
|
[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 ;).
|
||||||
Reference in New Issue
Block a user