Tree @master (Download .tar.gz)
- ..
- ansible.md
- classes.md
- commands.md
- design.md
- diff.md
- direction-and-position.md
- dividers.md
- documentation.md
- environment-variables.md
- existing-scripts.md
- first-steps.md
- index.md
- install.md
- manpage.md
- moulti-functions.md
- progressbar.md
- python-scripting.md
- questions.md
- saving-and-loading.md
- scrolling.md
- shell-scripting.md
- steps.md
- subcommands.md
- technical-requirements.md
- text-search.md
- threads.md
- tools.md
- why-this-name.md
moulti-functions.md @master — view markup · raw · history · blame
Shell functions
Moulti offers a library of bash helpers named moulti-functions.bash, which should be available through $PATH.
Usage: source moulti-functions.bash
Functions
moulti_tool_is_available
Usage: moulti_tool_is_available command_name
Return whether the given command name is available (either in $PATH or as a shell built-in).
!!! example
```bash
if moulti_tool_is_available rg; then
echo "ripgrep is available"
fi
```
moulti_any_tool_is_available
Usage: moulti_any_tool_is_available "cmd_name_1|cmd_name_2|...|cmd_name_n"
Return whether any of the given command names is available (either in $PATH or as a shell built-in).
!!! example
```bash
if moulti_any_tool_is_available 'ack|hgrep|rg'; then
echo "at least one of ack, hgrep or rg is available"
fi
```
moulti_check_requirements
Usage: moulti_check_requirements req_1 req_2 ... req_n
moulti_check_requirements checks all given requirements and displays a buttonquestion step if any is missing.
This is often needed when writing portable shell scripts.
If the end user clicks "No", this function calls exit 1, thus ending the calling script.
Otherwise, it returns whether all requirements are met.
There are three ways to specify a requirement:
- stating a single command name
- stating multiple alternative command names separated with pipe characters
-
stating a command to run along with its expected return code:
ret:expected-return-code:arbitrary-shell-command
!!! example
```bash
moulti_check_requirements 'grep' 'qemu-system-arm64' 'rg|hgrep|ack' \
'ret:0:qemu-img --help | grep -w bitmap'
```
This ensures that:
- `grep` is available
- `qemu-system-arm64` is available
- `rg`, `hgrep` or `ack` is available
- `qemu-img` features the "bitmap" subcommand
moulti_python
Usage: moulti_python python_arguments
Depending on the underlying operating system, calling python may not work: some OS offer Python as python3, others as e.g. python3.12.
moulti_python tries:
python3python3.10,python3.11,python3.12, etc.python
!!! example
```console
$ source moulti-functions.bash
$ moulti_python --version
Python 3.13.2
```
moulti_iso_date
Usage: moulti_iso_date
moulti_iso_date outputs the current date, time and timezone, with millisecond precision.
!!! example
```console
$ source moulti-functions.bash
$ moulti_iso_date
2025-02-27T16:36:09.758+01:00
```
Under the hood, moulti_iso_date tries:
- date --iso-8601=ns
- gdate --iso-8601=ns
- Perl module Time::HiRes
- Python module datetime
moulti_duration
Usage: moulti_duration timestamp1 timestamp2
moulti_duration prints the amount of time elapsed between the given timestamps, with millisecond precision.
Both timestamps should use the same format as moulti_iso_date.
!!! example
```console
$ source moulti-functions.bash
$ moulti_duration '2025-02-27T16:36:09.758+01:00' '2025-02-28T19:38:50.312+01:00'
1 day, 3:02:40.554
```
moulti_exec
Usage: moulti_exec command
moulti_exec makes it easy to turn a command (or shell function) into a dedicated Moulti step with various bells and whistles.
Specifically, moulti_exec:
- creates a Moulti step using the given command as title, the current date and time as top text and "still running..." as bottom text;
- runs the given command with both stdout and stderr passed to that step, with scroll-on-activity enabled;
- waits until the command has finished running;
- updates the bottom text to reflect the current date and time, the return code and the amount of time the command took;
- sets the
successorerrorclass depending on the given command's return code; - disables scroll-on-activity;
- collapses the step after
STEP_COLLAPSE_ON_SUCCESSseconds if the return code is 0 andSTEP_COLLAPSE_ON_SUCCESSis set; - returns the same return code as the command.
This behavior can be further controlled by setting the following variables before calling moulti_exec:
STEP_ID: id of the step to create; defaults to a pseudo-random number.STEP_ADD_ARGS: array of extra arguments passed tomoulti step addwhen creating the stepSTEP_PASS_ARGS: array of extra arguments passed tomoulti passwhen running the commandSTEP_UPDATE_ARGS: array of extra arguments passed tomoulti step updateafter the command has finished runningSTEP_COLLAPSE_ON_SUCCESS: how many seconds to wait before collapsing the step if the command succeeded
!!! example
```bash
moulti_exec true
moulti_exec false
moulti_exec rsync -av moulti/doc/ remote:/moulti-doc/
```

moulti_delayed_collapse
Usage: moulti_delayed_collapse step_id [duration]
Collapse the given step after the given duration (expressed in seconds), which defaults to 5 seconds.
This function is synchronous, so you may want to use & to run it in the background.
!!! example
```bash
moulti_delayed_collapse my_step 3 &
```
moulti_type
Usage: moulti_type moulti_arguments string
!!! Example
```bash
moulti_type moulti step update example --title "This text appears one character at a time"
```
!!! danger "Do not use moulti_type with add commands like moulti step add."
!!! danger "Do not use syntax --moulti-argument=string."
!!! success "Use syntax --moulti-argument string instead."
stdbuf
Usage: stdbuf command
stdbuf is a polyfill function.
It attempts to provide a counterpart to GNU coreutils' stdbuf on operating systems that do not offer it out of the box.
!!! info
This function is provided only on:
- NetBSD
- OpenBSD, but only if `unbuffer` is available
It is advised to ensure `stdbuf` is actually available using [moulti_tool_is_available](#moulti_tool_is_available) or [moulti_check_requirements](#moulti_check_requirements).
moulti_process_lines
Usage: moulti_process_lines
moulti_process_lines turns arbitrary text input into Moulti steps. To this end, it reads lines from stdin and matches them against MOULTI_NEW_STEP_PATTERN. If a line matches, it is passed to moulti_make_step, else it is passed to moulti_inspect_line.
!!! info "See Migrating existing scripts for detailed explanations."
moulti_make_step
Usage: moulti_make_step previous_step_id suggested_next_step_id current_line matched_substring [capture ...]
!!! info "You should not call this function but rather implement your own variant." See Migrating existing scripts, specifically the Create Steps section.
moulti_make_step is called each time moulti_process_lines() encounters an input line that matches MOULTI_NEW_STEP_PATTERN.
Its numerous arguments are meant to provide enough context to create a new step:
$1: previous_step_id: id of the previous step, or empty string if this function should create the first one$2: suggested_next_step_id: suggested step id$3: current_line: complete input line, without trailing CR/LF, that matched MOULTI_NEW_STEP_PATTERN and triggered the function call$4: matched_substring: subset of the input line that matched MOULTI_NEW_STEP_PATTERN$5, $6, ...: capture: 0 to n substrings resulting from MOULTI_NEW_STEP_PATTERN capturing groups
!!! danger "This function does not have to create a new step but, if it does, it MUST print the created step id on stdout."
moulti_inspect_line
Usage: moulti_inspect_line current_line current_step_id
!!! info "You should not call this function but rather implement your own variant." See Migrating existing scripts, specifically the Pass content section.
moulti_inspect line is called each time moulti_process_lines() encounters an input line that should be passed to the current step.
moulti_inspect_line may:
- keep the line untouched:
printf '%s\n' "$1" - adjust the line:
printf '%s\n' "foo ${1//bar/} baz"-- it is also possible to output multiple lines - discard the line:
return
Variables
MOULTI_NEW_STEP_PATTERN
Default value: ^([-=#@]+)(\s*)(.+?)\2\1$
This POSIX extended regex is meant to match lines that should be turned into steps. The matching itself is done by moulti_process_lines. Regex captures are passed to moulti_make_step.
The default pattern matches lines surrounded with an equal number of -, =, # or @ characters:
------ Title ------===== Title =====#### Title ####@@@ Title @@@
Whitespace between the title and these characters is optional but must remain symmetric:
------Title------===== Title =====#### Title ####@@@ Title @@@
Capturing groups:
-,=,#or@characters- whitespace between these characters and the title
- title
!!! info "See Migrating existing scripts, specifically the Match titles section."