frobulator.plo
[ p ] rompt [ l ] ine [ o ] verwrite:
Clears a defined number of lines above the current cursor position, wiping from that point down to the end of the screen — built on terminal_cursor_up and terminal_clear_down.
frobulator.plo 1
SHELL PARSER AND SCRIPTING FUNCTION LIBRARY
Frobulator is a custom shell parser and scripting function library, easy to use and understand, that streamlines your shell scripting projects.
Source one file and get colorized line markers, prompts, progress feedback, checkpoints, and file, network and package helpers for apt and dnf.
Version // 2026-10-23-1100
Frobulator is a shell parser and scripting function library. Source it at the top of a Bash script and every message, prompt, download, package install and checkpoint gets the same clean, colorized, 80 column output - all while making redundant and complex code bits a thing of the past.
The current set of assertions upon which Frobulator is built restricts its functionality to scripts exclusively, at least for the time being.
Frobulator is a single Bash file. Run it to install it to ${HOME}/.local/bin, then source it from your scripts - or let the bootstrap header do both.
curl -s -L get.frbltr.app > frobulator && bash frobulator
Running the script directly installs it - no arguments default to --install. Sourcing is unaffected: the options only apply when the file is executed.
./frobulator # install (default)
./frobulator --install # install
./frobulator --uninstall # uninstall - scripts using frobulator fetch it again on their next run
./frobulator --help # usage
. "${HOME}"/.local/bin/frobulator
The release is identified by the literal update="YYYY-MM-DD-HHMM" line at the top of the file. The bootstrap reads it as text (grep '^update=') and downloads a new copy when the online value sorts after the installed one - bump it, with a four digit time, for every release, including same day releases. version is derived from it.
Start every script with this header. It fetches the latest Frobulator with curl or wget, sources it once, escalates when needed and prints the script banner. The sections below it are the standard layout of a Frobulator script.
self_arguments keeps the original arguments for frobulator.escalate - spaces, quotes and empty arguments intact.get.frbltr.app replaces the local copy only when its update= line sorts after it.frobulator_loaded skips the download and sourcing when Frobulator is already loaded.list array feeds frobulator.require, which installs whatever command or package is missing.#!/bin/bash
# dependencies ─────────────────────────────────────────────────────────────────
script="$(basename -- "${BASH_SOURCE[0]}")"
# script arguments for escalation
self_arguments=("${@}")
if [ "${frobulator_loaded}" != "true" ]
then
echo
echo "[ > ] Checking..."
echo
# root through sudo keeps using the user's frobulator
if [ -n "${SUDO_USER}" ]
then
USER="${SUDO_USER}"
HOME="$(getent passwd "${SUDO_USER}" | cut -d ':' -f 6)"
fi
frobulator="${HOME}/.local/bin/frobulator"
frobulator_download="$(mktemp)"
mkdir -p "${HOME}/.local/bin"
# latest release - curl or wget - local copy replaced only by a newer one
curl -s -L -o "${frobulator_download}" get.frbltr.app 2> /dev/null ||
wget -q -O "${frobulator_download}" get.frbltr.app 2> /dev/null
version_online="$(grep -m 1 '^update=' "${frobulator_download}")"
version_local="$(grep -m 1 '^update=' "${frobulator}" 2> /dev/null)"
if [[ "${version_online}" > "${version_local}" ]]
then
mv -f "${frobulator_download}" "${frobulator}"
chmod +x "${frobulator}"
fi
rm -f "${frobulator_download}"
if [ ! -f "${frobulator}" ]
then
echo "[ ! ] Unable to fetch frobulator ── [ get.frbltr.app ]"
echo
exit 1
fi
source "${frobulator}"
fi
# superuser ────────────────────────────────────────────────────────────────────
frobulator.escalate
# script ───────────────────────────────────────────────────────────────────────
frobulator.script
# version ──────────────────────────────────────────────────────────────────────
version="YYYY-MM-DD"
# usage ────────────────────────────────────────────────────────────────────────
# variables ────────────────────────────────────────────────────────────────────
# defaults ─────────────────────────────────────────────────────────────────────
# functions ────────────────────────────────────────────────────────────────────
# update ───────────────────────────────────────────────────────────────────────
# frobulator.update
# frobulator.upgrade
# requirements ─────────────────────────────────────────────────────────────────
list=(
)
frobulator.require ${list[@]}
list=()
# configuration ────────────────────────────────────────────────────────────────
Every marker prints a message, an optional detail and an optional fill character on one line as wide as the terminal, followed by a blank line from frobulator.brk - scripts do not add echo after messages. Prompts stay on the same line for the answer.
| Marker | Command | Purpose | Color |
|---|---|---|---|
| [ i ] | frobulator.nil | empty marker line | white |
| [ i ] | frobulator.inf | information line | blue |
| [ ! ] | frobulator.wrn | warning line | orange |
| [ # ] | frobulator.msg | message line | navy |
| [ + ] | frobulator.add | add/create line | lime |
| [ - ] | frobulator.rem | remove/delete line | crimson |
| [ ● ] | frobulator.ret | retain/keep line | aqua |
| [ ○ ] | frobulator.rel | release line | teal |
| [ ▷ ] | frobulator.fwd | forward/progress line | silver |
| [ ◁ ] | frobulator.rev | reverse/back line | silver |
| [ □ ] | frobulator.stp | stop line | grey |
| [ ▽ ] | frobulator.dwl | download line | magenta |
| [ △ ] | frobulator.upl | upload line | purple |
| [ □ ] | frobulator.lnk | link line | yellow |
| [ ✓ ] | frobulator.scs | success line | green |
| [ 𐄂 ] | frobulator.err | error line | red |
| [ > ] | frobulator.ins | insert/input line | teal |
| [ ¤ ] | frobulator.cpt | complete line | magenta |
| [ / ] | frobulator.url | url line | silver |
| [ ? ] | frobulator.qst | question prompt (no newline) | fuschia |
| [ + ] | frobulator.ipt | input prompt (no newline) | pink |
| [ ~ ] | frobulator.usr | user prompt (no newline) | grey |
| [ ↵ ] | frobulator.rtn | return prompt (no newline) | aqua |
frobulator.nul keeps the color of the line above, frobulator.ind clears it - both rejoin the line above so details stay together.frobulator.ltr and frobulator.num print lettered and numbered steps, optionally in a palette color.frobulator.sep prints a full width line, uncolored unless a palette color is given.frobulator.ntf frames a title and message in square, round, heavy, double, dots, matrix, tech, skel or ascii style.Markers accept direct strings, variables, arrays, command substitutions or values generated elsewhere in the script. All of them are normalized through frobulator.pmt, so alignment, wrapping and span generation stay consistent.
frobulator.inf "Checking dependencies" "[ curl ]"
prompt_arguments=(
"Checking dependencies"
"[ curl ]"
)
frobulator.inf "${prompt_arguments[@]}"
Every palette color has its own line command, and its name is accepted wherever a color is: numbered steps, separators and the critter. Colors are set only when output is a terminal - through tput, or ANSI sequences without it - and stay empty otherwise.
frobulator.palette adds a named color at run time from a 256 color code. Adding an existing name updates its color. The colors shown here follow a dark terminal theme, with the darkest codes lifted for reading: your terminal decides how they look.
frobulator.palette cornflower 68
frobulator.num cornflower 1 "Soft blue line" "[ value ]"
Frobulator replaces the if [ "${?}" -ne 0 ] blocks of a script with one line checks. Failures are recorded, logged to ~/.local/var/log/<script>-<stamp>.log and summed up at the end.
| Command | On failure |
|---|---|
frobulator.complete | Reports Incomplete - <label>, logs the failure and carries on |
frobulator.complete halt | Logs, prints the summary and exits the script - also inside a function |
frobulator.halt | Prints the message and exits with the failed command's own status |
frobulator.fail | Returns the failed status inside a function - follow it with || return |
frobulator.track | Records the failure in the calling function's status |
frobulator.result | Reports overall success or the failure count, then clears the records |
zipalign -p -f 4 "${file_unsigned}" "${file_aligned}"
frobulator.complete halt "Align failed" "[ ${file_aligned} ]"
rm -f "${cache}"
frobulator.complete
frobulator.complete "${checkpoint_directory}" "make-all" make all
frobulator.result "${script}"
The checkpoint form runs a command once: it is skipped while "${path}/${checkpoint}" exists, and the checkpoint file is only created on success. Run the script again after a failure and it resumes where it stopped.
The package manager is picked from the distribution family in /etc/os-release: debian and its derivatives use apt, fedora and its derivatives use dnf, or yum when dnf is missing. The family decides, not the commands on the PATH, so a Fedora container under Termux uses dnf even with Termux's apt in reach.
| Command | apt | dnf |
|---|---|---|
frobulator.update | apt-get update | dnf makecache |
frobulator.upgrade | apt-get dist-upgrade | dnf upgrade |
frobulator.install | apt search, then install | dnf install |
frobulator.require | apt-file search | dnf repoquery --whatprovides |
frobulator.reinstall | apt-get install --reinstall | dnf reinstall |
frobulator.purge | apt-get purge --autoremove | dnf remove |
frobulator.hold | apt-mark hold | dnf versionlock add |
frobulator.release | apt-mark unhold | dnf versionlock delete |
frobulator.clean | autoremove, autoclean, clean | dnf autoremove, dnf clean all |
frobulator.require checks commands and installed packages first and only touches the package manager when something is missing, so requirements that are already met need no root access. Package name globs such as "libssl*" install every match.
frobulator.permissions sets the exact mode from a scope and optional modifiers, in place of raw chmod numbers. Directories always keep execute for whoever can read them.
| call | file | directory | typical use |
|---|---|---|---|
public | 644 rw-r--r-- | 755 rwxr-xr-x | regular files, configs, shared data |
public execute | 755 rwxr-xr-x | 755 rwxr-xr-x | scripts, binaries, installed tools |
public readonly | 444 r--r--r-- | 555 r-xr-xr-x | reference files that should not change |
public readonly execute | 555 r-xr-xr-x | 555 r-xr-xr-x | locked-down tools |
group | 640 rw-r----- | 750 rwxr-x--- | files for your group only |
group execute | 750 rwxr-x--- | 750 rwxr-x--- | group-only scripts |
group readonly | 440 r--r----- | 550 r-xr-x--- | group reference files |
group readonly execute | 550 r-xr-x--- | 550 r-xr-x--- | locked group tools |
private | 600 rw------- | 700 rwx------ | credentials, keys, tokens |
private execute | 700 rwx------ | 700 rwx------ | personal scripts |
private readonly | 400 r-------- | 500 r-x------ | ssh keys, certificates |
private readonly execute | 500 r-x------ | 500 r-x------ | locked personal tools |
frobulator.permissions public execute "${path}/${file}"
frobulator.permissions private readonly "${HOME}/.ssh/id_ed25519"
All 110 Frobulator functions with their arguments and examples. Search them, or pick a group.
[ p ] rompt [ l ] ine [ o ] verwrite:
Clears a defined number of lines above the current cursor position, wiping from that point down to the end of the screen — built on terminal_cursor_up and terminal_clear_down.
frobulator.plo 1
[ p ] rompt [ m ] anagement [ t ] ool:
The shared prompt-formatting engine behind every color and marker command. Normalizes 1–3 arguments (begin, end, span character) into a line as wide as the terminal (columns_terminal, never below 80): pads/fills the middle span, folds begin with word-detection when it would overflow the line, and truncates an overlong end with an ellipsis while preserving its surrounding bracket style - a [ 'name' // value ] bracket keeps its whole // value ] tail (and the closing quote), so only the name is shortened. Populates the prompt_string array consumed by every wrapper below rather than printing directly.
frobulator.pmt "Downloading" "[ package.tar.gz ]"
Line break: prints the blank line that follows every marker line and notice block, and flags it so the carry-over markers (frobulator.nul, frobulator.ind) can rejoin the line above instead. Called by the markers themselves - use it directly only after your own echo output. It also adds the marker line and its blank line to lines_printed_terminal (wrapped rows counted at the real terminal width), which frobulator.escalate uses to clear its output.
frobulator.brk
Letter.
Prints a lettered step marker — first argument is the letter, remaining arguments are forwarded to frobulator.pmt.
frobulator.ltr a "Select source directory"
Number.
Prints a numbered step marker — first argument is the number, remaining arguments are forwarded to frobulator.pmt. An optional palette color before the number prints the number and the line in that color - e.g. green for files to add and red for files to remove, matching their frobulator.add / frobulator.rem headers.
frobulator.num 1 "Install dependencies"
frobulator.num lime 1 "new-track.mp3"
frobulator.num crimson 2 "old-track.mp3"
Separator.
Prints a full-width separator line built from frobulator.pmt. The line is uncolored unless an optional palette color is given first, which prints the line and its text in that color.
frobulator.sep
frobulator.sep lime "Section"
Notify.
Prints a framed notice block. Optional leading arguments select a frame style (square [default], round, heavy, double, dots, matrix, tech, skel, ascii), the split keyword (renders title and message as two separate frames instead of one divided frame), and a marker-type keyword (inf, wrn, scs, err, etc.) to color the title using that marker's color. Remaining arguments are title then message; a second marker-type keyword placed between them colors the message. Like the line markers, the block is followed by a blank line.
frobulator.ntf round inf "Notice" "The setup process is ready."
frobulator.ntf heavy split err "Failure" "Could not reach the update server."
frobulator.ntf wrn "Disclaimer" inf "This action is permanent."
Empty (nil) line. Prints a empty marker line with the [ i ] marker in white.
frobulator.nil "Message" "[ detail ]"
Information. Prints a information line with the [ i ] marker in blue.
frobulator.inf "Message" "[ detail ]"
Warning. Prints a warning line with the [ ! ] marker in orange.
frobulator.wrn "Message" "[ detail ]"
Message. Prints a message line with the [ # ] marker in navy.
frobulator.msg "Message" "[ detail ]"
Add. Prints a add/create line with the [ + ] marker in lime.
frobulator.add "Message" "[ detail ]"
Remove. Prints a remove/delete line with the [ - ] marker in crimson.
frobulator.rem "Message" "[ detail ]"
Retain. Prints a retain/keep line with the [ ● ] marker in aqua.
frobulator.ret "Message" "[ detail ]"
Release. Prints a release line with the [ ○ ] marker in teal.
frobulator.rel "Message" "[ detail ]"
Forward. Prints a forward/progress line with the [ ▷ ] marker in silver.
frobulator.fwd "Message" "[ detail ]"
Reverse. Prints a reverse/back line with the [ ◁ ] marker in silver.
frobulator.rev "Message" "[ detail ]"
Stop. Prints a stop line with the [ □ ] marker in grey.
frobulator.stp "Message" "[ detail ]"
Download. Prints a download line with the [ ▽ ] marker in magenta.
frobulator.dwl "Message" "[ detail ]"
Upload. Prints a upload line with the [ △ ] marker in purple.
frobulator.upl "Message" "[ detail ]"
Link. Prints a link line with the [ □ ] marker in yellow.
frobulator.lnk "Message" "[ detail ]"
Success. Prints a success line with the [ ✓ ] marker in green.
frobulator.scs "Message" "[ detail ]"
Error. Prints a error line with the [ 𐄂 ] marker in red.
frobulator.err "Message" "[ detail ]"
Insert. Prints a insert/input line with the [ > ] marker in teal.
frobulator.ins "Message" "[ detail ]"
Complete. Prints a complete line with the [ ¤ ] marker in magenta.
frobulator.cpt "Message" "[ detail ]"
Url. Prints a url line with the [ / ] marker in silver.
frobulator.url "https://example.com"
Question prompt. Prints a question prompt with the [ ? ] marker in fuschia, and stays on the same line for the answer.
frobulator.qst "Enter value"
Input prompt. Prints a input prompt with the [ + ] marker in pink, and stays on the same line for the answer.
frobulator.ipt "Enter value"
User prompt. Prints a user prompt with the [ ~ ] marker in grey, and stays on the same line for the answer.
frobulator.usr "Enter value"
Return prompt. Prints a return prompt with the [ ↵ ] marker in aqua, and stays on the same line for the answer.
frobulator.rtn "Press to close" "[ konsole // 'weather' ]"
Null line - carry-over: keep color of the line above. Carry-over line: continue line, retain color. Rejoins the line above on screen, so a message and its details stay together.
frobulator.nul "continued output"
Index line - carry-over: without color. Carry-over line: continue line, clear color. Rejoins the line above on screen, so a message and its details stay together.
frobulator.ind "continued output"
Thin wrapper around frobulator.plo — erases a defined number of lines above the current cursor position the same way.
frobulator.erase 3
Sets columns_terminal - the width used by prompts, notifications, bars and images - from the terminal width (tput cols), never below columns_terminal_minimum (default 80), which is also used when output is not a terminal. Runs on load and again on every window resize (WINCH trap), so new output follows the window width.
columns_terminal_minimum=100
frobulator.columns
Each named color wrapper calls frobulator.pmt, stores its color into prompt_string and echoes the result, so every color line follows the same formatting rules as the markers.
frobulator.[color] "[string]" "[string]" "[span character]"
frobulator.lime "Highlighted" "[ value ]"
Adds a named color to the palette at run time from a 256-color code (0 to 255). The name is then accepted wherever a palette color name is - the optional color of frobulator.num and frobulator.sep, and the critter. Like the built-in colors, the sequence is set only when output is a terminal (via tput, or ANSI without it) and is empty otherwise. Adding an existing name updates its color.
frobulator.palette cornflower 68
frobulator.num cornflower 1 "Soft blue line" "[ value ]"
Prints a predefined frobulator.sep line (which prints its own blank line after it) — use to separate instructions or warnings from prompts.
frobulator.separate
Wraps the read builtin (forwarding all arguments to it) and prints a trailing blank line, so prompts stay evenly spaced after user input.
frobulator.qst "Continue?" "[ y/n ]"
frobulator.read reply
Prints a script startup banner: a msg-colored notice block titled Script showing Executing: '${script}' and Version:. An optional description is shown above them.
frobulator.script
frobulator.script "Welcome to the Gutendex terminal library!"
Prints a string one character at a time with a randomized delay between each, to emulate human typing. The first argument is the speed, a single digit from 0 to 9 (optional, defaults to 9). Each step adds 0.02 s to the maximum delay per character: 0 types at a steady 0.02 s, about one screen refresh, and 9 at up to 0.2 s. Every argument after it is printed, joined with spaces, so the string needs no quotes. When the first argument is not a single digit, it is part of the string.
frobulator.type 3 "Preparing environment..."
Sleeps for a number of seconds (defaults to 1 when omitted) — a simple pause between commands.
frobulator.timeout 5
Pauses for frobulator.timeout's default interval, then clears the terminal — used for script "paging" once a step's checkpoints are met.
frobulator.clear
Shows a live countdown before continuing, validating that the first argument is a non-negative integer. Remaining arguments are forwarded to frobulator.pmt as the message shown beside the counter.
frobulator.countdown 10 "Starting install" "[ press ctrl+c to cancel ]"
Generates a randomly colored, grammatically conjugated action prompt from a verb (e.g. download → Downloading..., panic → Panicking...), falling back to frobulate when no verb is given. Handles common English suffix rules (-ie → -y, silent -e drop, -ic → -ick, and final consonant doubling for one-syllable verbs ending consonant-vowel-consonant plus a short list of verbs stressed on the last syllable, e.g. strip → Stripping, submit → Submitting, but open → Opening) before appending -ing. Sets the prompt_progress/color_progress globals consumed by frobulator.progress. Callable directly, but normally invoked internally.
frobulator.action "download" "[ ${file} ]"
Waits on the most recently backgrounded process (${!}), animating a simple /\ ticker beside a message until it exits, then returns that process's exit status.
frobulator.background process "Updating package index" -- apt-get update
Called directly, it follows the job started just before it: apt-get update & then frobulator.process "Updating package index" — frobulator.background does both without the shell's job notices.
Same as frobulator.process, but generates its message via frobulator.action (so the first argument is a bare verb, not a pre-built message) and animates a smoother ⎺⎻⎼⎽⎼⎻ ticker.
frobulator.background download "[ ${file} ]" -- curl -L "${url}" -o "${file}"
Called directly, it follows the job started just before it: curl … & then frobulator.progress "download" "[ ${file} ]" — frobulator.background does both without the shell's job notices.
Runs a command (via "${SHELL}" -c) with a simulated activity bar — progress accelerates early, slows near 90%, and only reaches 100% once the process actually exits. Not a true byte-accurate progress meter.
frobulator.bar sleep 5
frobulator.bar apt-get update
frobulator.bar rsync -av source/ destination/
Creates one or more temporary directories (template frobulator.temporary.XXXXXX, via mktemp -d) and, for each, eval-assigns the resulting path back into the named variable you pass in — so the argument is a variable name, not a path. Several variable names can be passed; the caller's own variables are left untouched.
frobulator.temporary directory_temporary
# ${directory_temporary} now holds the generated path
Registers EXIT/HUP/INT/PIPE/QUIT/TERM traps that recursively delete the given directories on interruption or normal exit. Paths are fixed when the trap is set, and directories from every call are kept - so several temporary directories can be cleaned up. Use immediately after frobulator.temporary.
frobulator.temporary directory_temporary
frobulator.trap "${directory_temporary}"
One-line status check after a command, with frobulator.result once at the end of the script. The first argument picks what a failure means:
continue (default, also when omitted) - records the status, reports Complete - <label> or Incomplete - <label>, logs failures, and carries on.halt - same on success; on failure prints the message (or Incomplete - <label>), logs it, prints the frobulator.result summary and exits the script - also when called inside a function.An optional message and detail follow the keyword; the message replaces the label on failure. Without a message the label is the calling function's name (image_download → image download). At script level it is the previous command in the script (frobulator.write → write, cd → cd), or the action of frobulator.progress or frobulator.background (clone); assignments and lines it cannot read fall back to Operation N. Failures are written to the script's log (~/.local/var/log/<script>-<stamp>.log) through frobulator.silence log.
apk_tool_update
frobulator.complete halt
zipalign -p -f 4 "${file_unsigned}" "${file_aligned}"
frobulator.complete halt "Align failed" "[ ${file_aligned} ]"
rm -f "${cache}"
frobulator.complete
frobulator.result "${script}"
The checkpoint form runs a command once and skips it on later runs: frobulator.complete [ continue | halt ] "[path]" "[checkpoint]" command [arguments...] - skips the command if "${path}/${checkpoint}" exists, otherwise runs it, records its status and creates the checkpoint file on success. On failure the stale checkpoint is removed; halt then prints the summary and exits.
frobulator.complete "${checkpoint_directory}" "make-all" make all
frobulator.complete halt "${checkpoint_directory}" "image-checkpoint" download_image
Stops the script when the command that ran immediately before it failed - the stop behind frobulator.complete halt, also callable directly - a one-line replacement for an if [ "${?}" -ne 0 ] block ending in exit. On success it records the status for frobulator.result and continues silently. On failure it prints the optional message with frobulator.err, writes a dated line to the script's log through frobulator.silence log (~/.local/var/log/<script>-<stamp>.log), and exits with the failed command's own status.
zipalign -p -f 4 "${file_unsigned}" "${file_aligned}"
frobulator.halt "Align failed" "[ ${file_aligned} ]"
mkdir -p "${directory}"
frobulator.halt
Same as frobulator.halt, for use inside functions: instead of exiting the script it returns the failed status, so the caller keeps control. Follow it with || return to leave the calling function - a function cannot make its caller return on its own.
build () {
make all
frobulator.fail "Build failed" "[ ${target} ]" || return
}
One-line replacement for an if [ "${?}" -ne 0 ]; then status=1; fi block inside a function: records the failure of the command that ran immediately before it in the calling function's status, and returns that command's own exit status - so it can be chained to leave a loop or the function.
build () {
local status=0
make all
frobulator.track
make install
frobulator.track || return 1
return "${status}"
}
Evaluates every status recorded by frobulator.complete since the last call, reports overall success or a failure count (pointing at the log directory on failure: ${HOME}/.local/var/log/, or ${PREFIX}/var/log/ for a system-context run - the same directory frobulator.silence log writes to), then clears the recorded checkpoint/status collections. Use in tandem with frobulator.complete.
frobulator.result setup
Creates a directory (and sets ownership via frobulator.ownership) from a path/name or array. With a single argument containing a /, the path is split automatically (parent directory vs. final segment) — so a single absolute path works correctly here, unlike some of the item-based helpers below.
frobulator.directory "${HOME}/.config" "frobulator"
frobulator.directory "${HOME}/.config/frobulator"
Writes content to one or more files under path (path defaults to ${PWD} when a 3-argument call is used), creating the directory first if needed, and sets ownership on each written file. mode controls how content is applied:
append — adds content to the end of the filewrite — overwrites the file entirelyprepend — adds content before the file's existing contentsfrobulator.write append "enabled=true" "${HOME}/.config/frobulator" "config"
Creates one or more empty files (via touch) under path (path defaults to ${PWD} when a single-argument call is used) and sets ownership on each.
frobulator.file "${HOME}/.config/frobulator" "config"
Reverse-selects: cds into path, then deletes every item in that directory except the file(s)/array you list — the inverse of frobulator.delete.
frobulator.keep "${HOME}/Downloads" "important.zip"
Deletes selected item(s) from a directory. A single argument is treated as an item relative to ${PWD} (unlike frobulator.directory, it does not auto-split a /-containing single argument into path + item — pass the base path and item separately, or use dirname/basename, when deleting an absolute path). Two arguments treat the first as the base path and the second as the item or array of items. Warns instead of silently succeeding when the resolved target doesn't exist.
frobulator.delete "${temporary_directory}" "old-file.tmp"
list=( adb fastboot )
frobulator.delete "${directory_android}" list
Recursively copies file(s)/directories: frobulator.copy "[source]" "[target]" "[file]" | "[array]". Creates target if missing.
frobulator.copy "${source_directory}" "${target_directory}" "config"
Moves file(s)/directories, then sets public execute permissions (755) on the moved item(s) at the target via frobulator.permissions. source defaults to ${PWD} per item if left empty.
frobulator.move "${source_directory}" "${target_directory}" "archive.tar.gz"
Creates symbolic links, detecting and labeling whether each source item is a file or directory in its status output, then sets ownership on the created link. Three call forms:
frobulator.link "[source]" "[target]" "[item]" — link a single item, same name at targetfrobulator.link "[source]" "[target]" "[item]" "[link name]" — link a single item under a different namefrobulator.link "[source]" "[target]" "[array]" (more than 4 total arguments) — link every item in the array, same namesfrobulator.link "${directory_platform_tools}" "${HOME}/.local/bin" "adb"
Displays a local or remote image directly in supported terminals (local file path, http(s):// URL, or stdin). Width defaults to terminal width and cells/percentages are accepted; specifying an explicit height disables automatic aspect-ratio preservation.
frobulator.image "${image_file}"
frobulator.image "${image_file}" 50%
frobulator.image "${image_file}" 80 40
Fetches the HTTP status code for a URL into ${status_url} — silently, via curl --write-out. Called with one argument it checks the URL as-is; called with two (url, data) it checks "${url}/${data}" following redirects. Use before frobulator.status.
frobulator.http "https://example.com/file.tar.gz"
Interprets ${status_url} (set by a prior frobulator.http call) into a 1xx/2xx/3xx/4xx/5xx category, prints a colored status line accordingly, and sets ${proceed} to 1 (ok to continue) or 0 (abort) plus ${reason} (client/server/response) on failure.
frobulator.http "https://example.com/file.tar.gz"
frobulator.status
Lists the file names at the top level of a GitHub repository through its contents listing (curl only - names extracted with grep and cut). An optional prefix keeps only names starting with it. Names are stored in the frobulator_return array (reset on each call); an unreachable listing or no matching name is an error and makes the function return 1. Pair with frobulator.download to fetch the listed files.
frobulator.repository "nathaneltitane/terminal" "bash-function-"
frobulator.download get.trmnl.me "${HOME}"/.local/bin "${frobulator_return[@]}"
Downloads file(s), one request per item, reported by the HTTP status code of the download itself (2xx is success; any other code, or an unreachable server, is an error and makes the function return 1). Each file is written to a partial file beside the target and only moved into place on success, then set to public execute (755) via frobulator.permissions. Missing directories are created. The caller's arrays are left untouched.
Call forms:
"[url]" "[directory]" "[item]" | "[array]" - each item from "[url]"/"[item]" into the directory. A single item is fetched from the url itself when the url already ends with the item or with a file name (extension) - so the item becomes the saved name."[url]"/"[item]" "[directory]"/"[item]" - the url is the file, saved under the given path."[url]"/"[item]" "[directory]" - the url is the file, saved under its own name."[url]" "[source item]" "[directory]" "[item]" - "[url]"/"[source item]" saved under a different name.Every message ends its bracket with // <status code> - 000 when no response was received. A server that does not answer within 30 seconds is reported as unreachable.
frobulator.download get.frbltr.app "${HOME}/.local/bin/frobulator"
list=( "dextop" "dextop-additions" )
frobulator.download get.dxtp.app "${HOME}/.local/bin" "${list[@]}"
frobulator.download "https://dl.winehq.org/wine/wine-mono/7.4.0/wine-mono-7.4.0-x86.msi" "${HOME}/Downloads" wine-mono.msi
Uploads data or file(s), one request per item. First argument is the HTTP request method (POST, PUT, etc.), second is the URL, remaining argument(s)/array are payloads — a {...} or [...] JSON string is sent with a JSON content type, an @file argument is sent as multipart form data, anything else is sent as URL-encoded form data. Each upload runs with a frobulator.progress "upload" indicator and is reported by the HTTP status code of the upload itself (2xx is success; any other code, or an unreachable server, is an error and makes the function return 1). Every message ends its bracket with // <status code> - 000 when no response was received (unreachable server - no answer within 30 seconds - or the request was never sent). The caller's arrays are left untouched.
frobulator.upload POST "https://example.com/upload" "${archive_file}"
frobulator.upload POST "https://example.com/upload" '{"key":"value"}'
list=( "name=one" "name=two" )
frobulator.upload PUT "https://example.com/items" "${list[@]}"
Runs a command (given as one string, via "${SHELL}" -c) with all its output out of sight. By default stdout and stderr go to the null sink. With log first, they are appended to the script's timestamped log file instead — ${directory_log}/${script}-${stamp}.log, where directory_log is ${PREFIX}/var/log for a system-context run or ${HOME}/.local/var/log otherwise. It runs in the foreground; to show a ticker while it runs, start it through frobulator.background.
frobulator.silence "apt-get update"
frobulator.silence log "apt-get install --assume-yes curl"
Runs a command in the background without the shell's job notices — no [1] 12345 when it starts and no [1]+ Done when it ends, even in an interactive shell where a bash function calls it. Job control is switched off while the command runs and restored afterwards; only the job start notice goes to the null sink, so the command's own errors still reach the terminal. The command is given as separate arguments after --, so paths and patterns pass through untouched.
--, it shows a frobulator.progress ticker until the command ends and returns the command's exit status. The command's stdout goes to the null sink, since the ticker owns the line.--, the command is left running detached and its process identifier is stored in frobulator_return. Its output is left as is; redirect the whole call to silence it.Options, in this order, before the action:
quiet — the command's errors go to the null sink as well.process — use the frobulator.process ticker with free text instead of the frobulator.progress action verb.output "[file]" — write the command's stdout to that file instead of the null sink, to read once the ticker ends.frobulator.background download "[ ${file} ]" -- curl -s -L -o "${file}" "${url}"
frobulator.background quiet generate -- blender --background "${file_model}"
frobulator.background process "Stopping display server" -- x11vnc -R stop
frobulator.background output "${file_status}" download -- curl -s -o "${file}" -w "%{http_code}" "${url}"
frobulator.background install -- frobulator.silence log "apt-get install --assume-yes curl"
frobulator.background -- mpv --no-terminal "${file_audio}"
Captures masked password input character-by-character, showing • per keystroke and handling backspace/delete, until Enter. Result is stored in ${password} (and returned via ${input} as well).
frobulator.password
Captures one or more prompted values by label. Labels containing password are captured with frobulator.password; everything else uses a plain read. Re-prompts on empty input. Results accumulate in the frobulator_return array as label=value pairs.
options=( "username" "password" )
frobulator.input "${options[@]}"
Prints the package manager command for an action: update, upgrade, install, reinstall, purge, autoremove, autoclean, clean, hold or release. Prints nothing when the manager has no equivalent (dnf has no autoclean).
command_install="$(frobulator.manager install)"
Prints install ok installed when the package is installed - read from rpm under dnf/yum and from dpkg-query under apt.
frobulator.installed curl
Runs apt-get autoremove, autoclean, and clean in sequence (each shown with its own progress indicator), then clears stale dpkg post-install scripts under ${PREFIX}/var/lib/dpkg/info to avoid package configuration errors. Under dnf: dnf autoremove and dnf clean all.
frobulator.clean
Marks package(s) for version freeze via apt-mark hold. Under dnf: dnf versionlock add - built into dnf5 (Fedora 41 and later), a plugin on dnf4 (python3-dnf-plugin-versionlock).
frobulator.hold firefox-esr
Reverses frobulator.hold via apt-mark unhold. Under dnf: dnf versionlock delete.
frobulator.release firefox-esr
Runs a background apt update && apt full-upgrade (dnf makecache and dnf upgrade under dnf), then sequentially updates/upgrades/installs each named package — a heavier pre-flight pass meant to avoid "not found" or "ignored" errors on the install(s) that follow.
frobulator.failsafe curl
Installs package(s). A .deb or .rpm path is installed directly; otherwise the package is looked up with apt search first, and installation is skipped (with a "present on system" message) if it's already installed.
frobulator.install curl
Checks whether each name is available as a command or as an installed package (dpkg-query), and if neither, searches apt-file to find and install the package that provides it. apt-file is only installed and refreshed when something is actually missing, so requirements that are already met need no root access — supports * glob package-name queries too, expanding them against apt-cache pkgnames before installing every match. Under dnf the installed check reads rpm, the providing package comes from dnf repoquery --whatprovides on /usr/bin and /usr/sbin and globs expand through dnf repoquery - no apt-file needed.
frobulator.require curl
frobulator.require "libssl*"
Reinstalls package(s) via apt-get install --reinstall (dnf reinstall under dnf).
frobulator.reinstall curl
Runs apt-get update (dnf makecache under dnf) with a progress indicator.
frobulator.update
Runs apt-get dist-upgrade (dnf upgrade under dnf) with a progress indicator.
frobulator.upgrade
Purges package(s) via apt-get purge --autoremove (dnf remove under dnf), but only if apt search shows the package as currently installed (skips with a message otherwise).
frobulator.purge unused-package
Opens a native directory-selection dialog via zenity (GNOME) or kdialog (KDE), whichever is available, with ${script} in the window title, and prints the selection (one path per line) for capture. Extra arguments are passed on to the dialog tool. Fails with a warning if neither is installed.
directory="$(frobulator.dialog "Directory")"
Forcefully and repeatedly pkill -f's a process name/pattern until pgrep -f no longer finds it. Requires both pgrep and pkill.
frobulator.terminate rogue-process
Cleanly exits the current script or process instance — runs a 3-second frobulator.countdown ("Exiting"), then calls the exit builtin with an explicit exit code (defaults to 0, or 1 if the countdown itself was interrupted). Does not touch the shell — see frobulator.close for that behavior. Being terminal, it never returns to its caller like the rest of the library does.
frobulator.exit setup
frobulator.exit setup "${status}"
Runs the same 3-second frobulator.countdown, then forcefully terminates the current ${SHELL} via frobulator.terminate — this ends the shell session, not just the calling script. (This is what frobulator.exit used to do before the two were split.)
frobulator.close setup
Prints the active shell user (${SUDO_USER} if set, otherwise ${USER}) and pauses 1 second — useful before privilege-sensitive steps.
frobulator.user
Checks whether the listed command(s) exist. If run as root, installs any missing ones via frobulator.require and asks the person to restart as their normal user. If not root, prompts to escalate (frobulator.escalate) for any missing command, or warns and fails if declined.
requirements=( curl git )
frobulator.assess "${requirements[@]}"
Relaunches the current script as root via sudo, preserving the original arguments (read back from the self_arguments array set by the bootstrap header - spaces, quotes and empty arguments are kept exactly; a plain string from older headers is still word split). If already root, resolves the correct non-root USER/HOME from SUDO_USER instead of re-launching. Before restarting it clears the bootstrap header and its own messages (3 header lines + lines_printed_terminal); the restarted run then clears its own header and the sudo password prompt, so only the escalated runtime messages stay on screen.
self_arguments=("${@}")
frobulator.escalate
Declares frobulator as loaded in the current shell by setting frobulator_loaded="true" - the bootstrap header checks it to skip downloading and sourcing again. Runs automatically when frobulator is sourced.
frobulator.self
Manages a systemd service, scoping automatically to --user or system context depending on whether the runtime is escalated (root). A single argument is treated as a daemon-level action with no target unit; two arguments target a specific service with the given action forwarded to systemctl. activate runs a full enable/start cycle with status verification. reload is the only action that doesn't require a service. Supported actions: reload, status, activate, enable, disable, start, stop, restart.
frobulator.service reload
frobulator.service reload "${service}"
frobulator.service activate "${service}"
Restores ownership on a target after privileged operations. Resolves the real path and classifies it: paths under the invoking user's home directory are attributed to that user; paths under system directories (/root, /usr, /etc, /var, /opt, /boot) are attributed to root; anything else falls back to the invoking user. Applied recursively via chown. Called internally by frobulator.directory, frobulator.write, frobulator.file, and frobulator.link.
frobulator.ownership "${directory_android}" "${HOME}/.local/bin/adb"
Sets file / directory permissions from a scope and optional modifiers, in place of raw chmod modes. Takes the scope first, then any modifiers (any order), then one or more targets (or an array). Sets the exact mode; directories always keep execute for whoever can read them, since a directory cannot be opened without it.
public (you edit, everyone reads), group (you edit, your group reads, no access for others), private (only you)execute (whoever can read can also run), readonly (nobody edits, including you)| call | file | directory | typical use |
|---|---|---|---|
public | 644 rw-r--r-- | 755 rwxr-xr-x | regular files, configs, shared data |
public execute | 755 rwxr-xr-x | 755 rwxr-xr-x | scripts, binaries, installed tools |
public readonly | 444 r--r--r-- | 555 r-xr-xr-x | reference files that should not change |
public readonly execute | 555 r-xr-xr-x | 555 r-xr-xr-x | locked-down tools |
group | 640 rw-r----- | 750 rwxr-x--- | files for your group only |
group execute | 750 rwxr-x--- | 750 rwxr-x--- | group-only scripts |
group readonly | 440 r--r----- | 550 r-xr-x--- | group reference files |
group readonly execute | 550 r-xr-x--- | 550 r-xr-x--- | locked group tools |
private | 600 rw------- | 700 rwx------ | credentials, keys, tokens |
private execute | 700 rwx------ | 700 rwx------ | personal scripts |
private readonly | 400 r-------- | 500 r-x------ | ssh keys, certificates |
private readonly execute | 500 r-x------ | 500 r-x------ | locked personal tools |
frobulator.permissions public execute "${path}/${file}"
frobulator.permissions private "${HOME}/.git-credentials"
frobulator.permissions private readonly "${HOME}/.ssh/id_ed25519"
Creates an archive from a directory (defaults to ${PWD} when omitted). Supported type values: tar, tar.gz/tgz, tar.bz2/tbz2, zip, 7z, rar — each checked and installed via frobulator.require before use.
frobulator.archive "backup" tar.gz "${HOME}/Documents"
Extracts a known archive type (detected from everything after the first period of the file name, so names like backup-1.2.tar.gz are not recognized) into directory (defaults to ${PWD} when omitted), installing the needed extractor (tar, 7z, unrar, unzip) via frobulator.require first.
frobulator.extract "backup.tar.gz" "${target_directory}"
No function matches your search.
These projects build their scripts on Frobulator.
Frobulator is written for GNU Bash, the shell environment on top of which the scripts function.
Frobulator is free software released under the GNU General Public License version 3.