Bashkit is an opiniated scripting model and framework for Bash 5.x. It is intended to help writing more robust scripts in which unhandled errors are preferably fatal. It does so by enforcing and exploiting selected bashisms and sometimes moving away from IEEE POSIX P1003.2/ISO 9945.2. It supplements bash as a collection of modules akin to a script development library. It consists mostly in pure bash functions with very few dependencies.
Bashkit is a scripting model that proposes idioms and tools for:
Bashkit comes with 7 core and 11 standard function modules. A bashkit script is a bash script that, at some point sources bashkit and modules and starts calling their functions. Custom modules are easy to write and module boilerplates are kept small. Nonetheless, a proper error handling surely requires editing.
Core modules implement:
Standard modules bring:
A module can be loaded either when sourcing
Bashkit
or by callingbashkit::load(1)
source bashkit.bash check shopt # load bashkit along with check and shopt modules
bashkit::load array # load array module
Stable releases can be found at wuage.
Documentation for Bashkit is available online. You may also find information on Bashkit by running TODO.
TODO
TODO
TODO
TODO
TODO
These definitions are used throughout the remainder of this manual.
POSIX
A family of open system standards based on Unix. Bash and Bashkit are
primarily concerned with the Shell
and Utilities portion of the POSIX 1003.1 standard.
blank
A space or a tab character.
builtin
A command that is implemented internally by the shell itself, rather
than by an executable program
somewhere in the file system.
control operator
A token that performs a control function. It is a newline or one of the
following:
‘||’, ‘&&’, ‘&’, ‘;’, ‘;;’, ‘;&’, ‘;;&’, ‘|’,
‘|&’, ‘(’, or ‘)’.
exit status or error code or errcode
The value returned by a command to its caller. The value is restricted
to eight bits,
so the maximum value is 255.
field
A unit of text that is the result of one of the shell expansions. After
expansion, when
executing a command, the resulting fields are used as the command name
and arguments.
filename
A string of characters used to identify a file.
job
A set of processes comprising a pipeline, and any processes descended
from it, that are
all in the same process group.
job control
A mechanism by which users can selectively stop (suspend) and restart
(resume) execution
of processes.
metacharacter
A character that, when unquoted, separates words. A metacharacter is a
space, tab, newline,
or one of the following characters: ‘|’, ‘&’, ‘;’, ‘(’, ‘)’, ‘<’,
or ‘>’.
name
A word consisting solely of letters, numbers, and underscores, and
beginning with a letter
or underscore. Names are used as shell variable and function names. Also
referred to as an
identifier.
operator
A control operator or a redirection operator. See Redirections, for a
list of redirection
operators. Operators contain at least one unquoted metacharacter.
process group
A collection of related processes each having the same process group
ID.
process group ID
A unique identifier that represents a process group during its
lifetime.
reserved word
A word that has a special meaning to the shell. Most reserved words
introduce shell flow
control constructs, such as for and while.
return status
A synonym for exit status.
signal
A mechanism by which a process may be notified by the kernel of an event
occurring in
the system.
special builtin
A shell builtin command that has been classified as special by the POSIX
standard.
token
A sequence of characters considered a single unit by the shell. It is
either a word or
an operator.
word
A sequence of characters treated as a unit by the shell. Words may not
include unquoted
metacharacters.
Bashkit is an acronym for Bourne-Again SHell KIT
. It
supplements Bash and can not be used without. This chapter briefly
summarizes the bashkit’s building blocks: logging, control
structures, functions, and how the shell executes commands with active
bashkit.
Bashkit as a proper software framework offers a logging system. A
bashkit script can and should record software events in a structured
way. Bashkit follows syslog(1)
levels to implement
logging routines:
routine | panic | alert | crit | error | warn | note | info | debug |
---|---|---|---|---|---|---|---|---|
level | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Logging level is controlled either by setting the global variable
$LOGLEVEL
beforehand or by calling
logging:setlevel
at runtime. Default logging level is
INFO/6
. As expected, a logging routine displays a message
when the current logging level is lower or equal to its own,
otherwise the message is silenced but planned side-effects occur (see
errcode
).
there’s a bashkit routine named
info
. It shadowsinfo(1)
the bash info document reader. If you need to useinfo(1)
, call it withcommand
info
[args]
.
bash-5.2$ cat hello.bash
#!/usr/bin/env bash
source ${SOME_PATH_TO_BASHKIT}/bashkit.bash
info 'hello world!'
bash-5.2$ bash -c ./hello.bash
2022-10-12 18:27:33+0200 [ info] ./hello.bash:3| hello world!
Standard logging happens on stderr
, when on a supported
terminal it is colorized by default. Whenever color is unsuitable, it
can be disabled by setting the global variable $NO_COLOR
.
As shown in hello.bash
example, standard logging routines
display a default format:
YYYY-MM-DD HH:MM:SS+hhmm [LEVEL] ORIGIN:LINENO| MSG
field | format |
---|---|
STAMP | ISO-8601 extended offset date-time format |
LEVEL | routine name in a padded string of length 5, enclosed in brackets |
ORIGIN | $FUNCNAME or $FILENAME or main or bash |
LINENO | integer of calling time $LINENO value |
MSG | arbitrary bash expandable string after “|” |
JSON logging happens on stderr
, it is enabled by setting
the global variable $JSON
beforehand. When activated, it
replaces standard logging output. Messages are emitted in NDJSON format and consist in valid json
values with no color and a fix layout:
Fields STAMP, LEVEL, …, MSG are similar to standard logging except for LEVEL that is not padded nor bracketed. They are all enclosed in double-quotes.
bash-5.2$ bash -c 'JSON=1 ./hello.bash'
{ "date": "2022-10-13 17:35:04+0200", "level": "info", "func": "./hello.bash", "lineno": "3", "text": "hello world!" }
bash-5.2$
panic
and fatal
are special logging
routines that stop the ordinary flow of control and begin
panicking:
panic
calls bash exit
with code 1fatal
calls bash exit
with a previously
set value (see errcode
)cleanup
functions (see trap
)
execute normally in LIFO order until the last onePanics can only be initiated by invoking panic
or
fatal
directly.
Report mode is controlled by setting the global variable
$REPORT
. When activated, the script will dump a stack-trace
and exit whenever an error is detected by bashkit.
Trace mode is controlled by $TRACE
. When activated:
xtrace
mode$PS4
report
mode is activatedDEBUG/7
Bashkit proposes a unique yet classical error handling coding patterns. They extend bash error semantic by exploiting conditional statements. They assemble into error handling pipelines. Bashkit uses a trap to catch errors as they arise. If they are handled locally, the flow of control proceeds. Otherwise, the error is bubbled up the calling stack until handled. When an unhandled error reaches its calling-stack root, the calling script usually crashes. In Bashkit, almost all errors are fatal.
Handling error in bash is difficult: The query “error handling in bash”, on the biggest search engine, returns +88M links as of October 2022. On SO, a closely related question, asked in 2008, was viewed +410k times and received answers as late as early 2022. Eventually, it was deemed “opinion-based” by moderators and closed to more answers.
Bash basic exit status handling is flawed by decisions made early
during bash design along with heavy POSIX constraints on the subject.
The resulting set -e
mode is unsatisfactory and
error-prone: whenever scripts are thought to fail fast, they could just
behave in unintuitive ways, fallen into one of the many bash
pitfalls.
Bashkit helps scripts to efficiently handle errors or fail fast in most of the cases. One should be aware that some bash quirks are simply unreachable to address within bash itself. Don’t do this:
Bashkit defines an error code mapping that closely follows bash definition and adds additional constraints to it:
$E_FAILURE
but not
E_FAILURE=1
range | names | owner | note |
---|---|---|---|
0-3 | E_SUCCESS - E_UNSUPPORTED | bash | |
4-7 | N/A | unused | |
8-32 | E_BASHKIT - E_CUSTOM | bashkit | highest bit is 3 or 4 |
33-123 | custom names | user | highest bit is 5 or 6 but err < 124 |
124-128 | E_TIMEOUT - E_INVALID_EXIT | bash | |
129-192 | E_SIGHUP - E_SIGRTMAX | signal | highest bit is 7 low bits for signum |
193-254 | N/A | unused | |
255 | E_OUT_OF_RANGE | bash |
bashkit offers tools to manipulate errors (see
error
)
Using true
as a control flow mechanism is already a bash
idiom:
#!/usr/bin/env bash
up_the_game
rm some_random_file_that_could_not_exist || true
echo "all went well!"
Under errcode
, the bashkit error handling system, you
can do the same:
source bashkit.bash
up_the_game
rm some_random_file_that_could_not_exist || true
echo "all went well!"
true
, is the most basic errcode handler
of
all. Using true
to handle an error means this error is
irrelevant to the flow of control.
return
andexit
are alsoerrcode
compatible so existing constructs are preserved.
command
is a bash builtin
. When used with
-v
option, it prints a description similar to the
type
builtin. It returns exit status 0
if
$cmd
is executable or fails with 1
if not. As
stated before, under errcode
(bashkit error handling
support) when $cmd
is not available, it is a fatal error.
To be more on point, check_cmd
should be more flexible than
silently failing (thanks to redirecting to /dev/null
), it
could at least log
an error. Consider the
bashkit idiom
to just do that:
check_cmd() {
local cmd=$1
command -v "${cmd}" &> /dev/null \
|| error "${cmd} not found"
}
bash-5.2$ bash -c 'source bashkit.bash; check_cmd(){... ; check_cmd inexistent'
2022-10-17 16:18:02+0200 [error] bash:1| inexistent not found
It is slightly better but still lacks some genericity: what if we
just want to know if a command exists and proceed with a workaround if
not? Enter raise
that ultimately enables more efficient
error handling patterns:
source bashkit.bash
check_cmd() {
local cmd=$1
command -v "${cmd}" &> /dev/null \
|| raise "${cmd} not found"
}
check_cmd inexistent \
|| error
Invoked like this, raise
position a message
along with the exit status
before returning to the
caller. It becomes the caller’s responsibility to chose what to do when
check_cmd
fails. For now, as previously, the script logs
the error and then crashes. But a more convenient flow is within reach
by using catch
:
source bashkit.bash
check_cmd isint \
|| {
catch
isint() {
printf '%d' "$1" > /dev/null 2>&1 \
|| raise "invalid number: $1"
}
}
isint 1 \
&& info integer \
|| error
In this situation, when check_cmd
raises a failure, the
catch
block is able to: 1) consume this failure 2) define a
replacement function
isint
also complies to errcode
: the last
invocation logs an informational “integer” (rather than error log
“invalid number”).
Now consider this example where maybe
has 50% chances of
failure:
source bashkit.bash
maybe()(( $1 < RANDOM%100 ))
maybe 50 \
&& echo yep \
|| echo nope # not an errcode handler
Bashkit error handling trap will stop short right after the
maybe
call if it fails. In the long run, the script prints
“yep” in one out of two runs but will never print “nope”. Under
errcode
it does not work because echo
is not
an errcode compatible handler. The idiomatic way here, is to
use resume
:
This time, the script will print either “yep” or “nope” with the same
frequency. resume
consumes the error and restores control
to the command that immediately follows, in this case:
echo nope
.
Because bash unary negation operator
!
is not a command,resume
can not transfer control to it. It can be replaced bynot
.not
is defined to return the logical negation of its argument.
source bashkit.bash
maybe()(( $1 < RANDOM%100 ))
abort()(( RANDOM & 0x1 ))
maybe 50 \
|| resume not abort \
|| error 'can not proceed'
In the long run, this script will rather succeed (75%) than log an error and fail (25%).
Bashkit favors fail fast
like scripting patterns: by
combining Conditional Constructs
[[...]]
and ((...))
with errcode
and handlers
scripts can achieve useful and robust
behaviors. Bashkit scripts can setup LIFO traps
on any
signal and cleanup
command easily enables deferred actions
upon script exit. It is also very easy to add text color
to
outputs.
Bashkit can detect a set but unhandled error that otherwise would go silent. In this case, the script will crit log the error:
When ran, the above script outputs:
Fail fast
is a simple technique that is known to ease finding most defects in a
software. A software that fails fast, will stop visibly as soon as a
problem occurs: bugs are easier to find and fix so, hopefully, fewer
make it to production.
Usually assertions
are different from exceptions in the
way that assertions can be turned off because they were believed useful
during design and tuning development stages. Experience has proven them
usefull even in production where real problems happen.
Bash has no support built-in support for assertions. Bashkit
which is mostly written in pure-bash does not either implement a
per-se assertion system: instead it emulates them
using conditional construcs
and errcode
:
Namely a tests followed by a || raise
pattern that exploits
raise
polymorphism is an
assertion
.
array::pick() {
local -n A=$1
local -n acc=${2:-__}
local i=$(( RANDOM % ${#A[@]} ))
printf -v acc '%s\n' "${A[i]}"
}
array::pick
takes two bash namerefs.
The first one points to an array A
while the second,
acc
, is used to write out a random element of
A
. Here are the things that could go wrong within this
function: 1) a wrong argument count (invocation mistake) 2)
A
not pointing to an array 3) A
pointing to an
empty array
Being a publicly exposed function of bashkit module
array
, array::pick
should remediate these
situations. The proper way is to add a bunch of tests akin to
assertions
and combine errcode handlers
to
always achieve a useful behavior:
source bashkit.bash
array::pick() {
(( $# == 1 || $# == 2 )) \
|| raise "${E_PARAM_ERR}" 'incorrect invocation' \
|| fatal
local -n A=$1
local -n acc=${2:-__}
check::vartype as A \
|| raise
(( ${#A[@]} != 0 )) \
|| raise "${E_PARAM_ERR}" 'array is empty'
local i=$(( RANDOM % ${#A[@]} ))
printf -v acc '%s\n' "${A[i]}"
}
This example also shows that
raise
is polymorphic.
- the first test asserts that there is either a single or 2 arguments, if not the script
fatals
immediately with exit status$E_PARAM_ERR
and a descriptive messagelocal refnames
assignations can not fail by design:$1
exists and$2
has a default- bashkit
check::vartype
enables script to assert that$A
refers to an array that has been set, if not the function (reraises thecheck::vartype
failure toarray::pick
caller- next test asserts a non-empty array and once again, raises any failure to
array::pick
caller- at this point, there is no way the function could fail anymore and it will eventually select and copy a random element from
$A[@]
to$acc
In Bash, a process may choose to perform a different action, rather than exiting, upon receiving a signal. This is done by setting up a signal handler (or trap). The trap must be set before the signal is received. A process that receives a signal for which it has set a trap is said to have caught the signal.
The simplest signal handling a process can choose to perform is to ignore a signal. This is generally a bad idea, unless it is done for a very specific purpose. Ignoring signals often leads to runaway processes which consume all available CPU.
Bashkit trap
module utilities extend bash command
behavior. Namely, trap::callback
enables a script to
register multiple callback functions or plain sources that are
called in LIFO order upon receiving selected signals.
More commonly, traps can be set up to intercept a fatal signal, perform cleanup, and then exit gracefully. For example, a program that creates temporary files might wish to remove them before exiting. If the program is forced to exit by a signal, it won’t be able to remove the files unless it catches the signal.
Bashkit cleanup
utility is a trap::callback
wrapper dedicated to hook instructions to signal EXIT/0
. It
can be called anytime from anywhere in the script, registered functions
will run in LIFO order at the script top level. As in bash, a mistake in
a callback could abort the entire cleanup process but won’t prevent the
script from exiting.
When
panicking
, a bashkit script willcleanup
before exiting. But there are situations beyond reach, like arithmetic exceptions or uncatchable signals that can preventcleanup
to take place.
Bashkit provides a color
module. For now, this module
only supports the ANSI 8 colors
model.
color::encode
supports a tiny english color description
language:
description = color "text" [ color "background" ]
| "reset"
color = ""
| attributes brightness base
attributes=? a list of unique modifiers ?
modifiers = ""
| "regular" | "bold" | "dim" | "italic" | "underlined"
| "blinking"
| modifiers, { modifiers }
brightness = ""
| "bright"
base = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan"
| "white" | "default"
The smallest descriptions of all are "text"
and
"reset"
. The later is always the ANSI ESC[m
reset code while the former is the current system-defined default.
source bashkit.bash
color::encode bold green text; bold_green=${__}
color::encode reset; reset=${__}
printf "%b%s%b" "${bold_green}" NATURE "${reset} does not hurry, yet everything is accomplished\n"
- descriptions are literals, they have no quote
- after a successful encoding, ANSI code is stord in
${__}
%b
is the required verb for an escape code when colorizing withprintf
- any compatible terminal that receives such codes will interpret them as color commands
Declaring colors can be a tidy task, the following example shows how to build a color palette:
source bashkit.bash
declare -A COLPAL=( # color palette
[panic]='underlined blinking bold white text red background'
[alert]='bold white text red background'
[crit]='underlined bold red text'
[fatal]='bold red text'
[error]='red text'
[warn]='yellow text'
[note]='blue text'
[info]='green text'
[debug]='magenta text'
[reset]='reset'
)
color::table COLPAL
The demonstrated palette is actually used by bashkit
logging
routines.
When called on a bash dictionary (ie. associative array),
color::table
will substitute, in place, each description by
a computed ANSI escape sequence. The resulting dictionary is to
be used later as a lookup table
.
bashkit::load - load a bashkit module
note [modname …]
With modname a string, bashkit:load
takes an
arbitrary number of modname arguments. modname refers
to a module named <modname>.bash
lying in the
hierarchy pointed by the environement variable $BASHKIT_MODPATH.
bashkit::load
returns success unless the module does not
exist.
$ bashkit load array
catch - store a raising errcode
and resume execution
catch [refname]
Catch captures and stores a raising errcode
and then
resume execution at the first following command.
If no refname is specified, errcode
is stored
in special bashkit variable $____
.
When catch
returns, the error context is modified:
$?
is equal to 0.
Catch always returns with an exit code of zero.
Example 1 true(1)
equivalence
The following command will never fail, it is equivalent to using
true(1)
.
$ rm "${TMPFILE}" || catch
Example 2 Error handling
The following command, in case of failure, will print an explanation
for curl(1)
exit statuses [1-3] or display it
otherwise.
$ curl "${URL}" > /dev/null 2>&1 || {
catch rc;
case ${rc} in
1) echo "unsupported Protocol";;
2) echo "failed to initialize";;
3) echo "malformed URL";;
*) echo "curl exited with status ${rc}";;
esac
}
raise(1)
, resume(1)
not - unary logical not as a function
not [command]
not
is the functional equivalent of !
. It
is intended to be used with resume(1)
that can only accept
a command as argument.
Example 1 Direct invocation
The first following command always fails while the second always succeeds.
$ not true
$ not false
Example 2 Combining with resume(1)
The following command is equivalent to logical
(green | ! red)
:
$ is_green "${color}" || resume not is_red "${color}"
resume(1)
raise - raise or reraise an errcode
raise [errcode] [errmsg]
Raise set an errcode and an errmsg and then fails immediately.
Raise returns the given errcode. If the specified
errcode is zero, the exit status defaults to one. When no
errcode is specified, raise
returns either the
last positionned errcode
or defaults to one if none.
If errmsg is not given, raise
uses the last
positionned one or defaults to none.
Example 1 Direct invocation
The following command always fails, here raise
is
equivalent to false(1)
.
$ raise
Example 2 Direct invocation with arguments
The first two commands fail with exit status 2, the last one with 1. In the last two, an error message is also positionned.
$ raise 2
$ raise 2 "error message"
$ raise "error message"
Example 3 Raising last exit status
The following commands will raise the exit status returned by
rm(1)
along with an error message for the second one.
$ rm "${TMPFILE}" \
|| raise
$ rm "${TMPFILE}" \
|| raise "cannot rm ${TMPFILE}"
Example 4 Raising exit status through calling stack
The following script will log an error and then exit with status 1.
The exit status is set in isint
and reused upon return by
error(1)
.
#!/usr/bin/env bash
# isint.bash -- bashkit example
source bashkit.bash
isint() {
local n
printf -v n '%d' "${1:-}" &> /dev/null \
|| raise "not an int"
}
isint "abc" \
|| error
$ bash isint.bash
2022-10-31 20:44:01+0100 [error] isint:8| not an int
Example 5 Relocating errors throughout calling points
In the above example, the error message traced back into
isint
. It is sometimes usefull to relocate the error at the
calling point:
#!/usr/bin/env bash
# isint.bash -- bashkit example
source bashkit.bash
isint() {
local n
printf -v n '%d' "${1:-}" &> /dev/null \
|| raise "not an int"
}
isint "abc" \
|| raise \
|| error
$ bash isint.bash
2022-10-31 20:47:38+0100 [error] isint.bash:13| not an int
catch(1)
, resume(1)
resume - abort a raising errcode
and resume
execution
resume [command]
Unlike catch(1)
, resume
executes in the
same context as the error. It allows the flow of control to
abort the raising errcode
and to recover execution by
running the command that follows it.
Example 1 Direct invocation
The following command always succeed, here resume
is
equivalent to builtin :
.
$ resume
Example 2 Direct invocation with a command argument
The following command displays a message, here resume
is
a no-op:
$ resume echo "resumed!"
Example 3 Error flow of control handling
$ (( n > 0 && n & 0x1 )) && echo "odd" || resume echo "even"
Without resume
the above command will stop short
before ||
for any even number: it will not display
“even”.
Example 4 Combining with not(1)
or builtin
let
resume
argument must be a command, unary
operator or litteral values are not supported. This is why we have to
use not(1)
in the following construct:
$ is_green "${color}" || resume not is_red "${color}"
The same goes for assignations:
$ is_even "${x}" || resume let x=$((x + 1))
catch(1)
, raise(1)
, not(1)
color::encode - compute an 8 colors ANSI code from a color description
color::encode [description]
color::encode
encodes a color description into an ANSI
color escape code. The code is always stored in special bashkit variable
$__
.
If no description is specified, the code defaults to
ESC[m
, the reset code.
The description must be written according to the following grammar:
description = color "text" [ color "background" ]
| "reset"
color = ""
| attributes brightness base
attributes=? a list of unique modifiers ?
modifiers = ""
| "regular" | "bold" | "dim" | "italic" | "underlined" | "blinking"
| modifiers, { modifiers }
brightness = ""
| "bright"
base = "black" | "red" | "green" | "yellow"
| "blue" | "magenta" | "cyan" | "white"
| "default"
The smallest descriptions of all are "text"
and
"reset"
. The later is always the ANSI ESC[m
reset code while the former is the current system-defined default.
color::encode
returns with an exit code of zero upon
successful encoding. It returns E_PARAM_ERR/9
otherwise.
The description must always be written without quote when invoking directly:
$ color::encode underlined blinking bold white text red background
$ echo "${__}"
\x1b[4;5;1;37;41m
https://en.wikipedia.org/wiki/ANSI_escape_code
color::table(1)
color::is_enabled - test if color is supported
color::is_enabled
color::is_enabled
test if color is not disabled
and terminal is compatible. One can disable color by setting
$NO_COLOR
before running scripts.
color::is_enabled
returns 0 if colors are available and
>0 otherwise.
$ color::is_enabled && echo "colors are available" || resume echo "no color"
color::encode(1)
, color::table(1)
color::table - compute 8 colors ANSI code from a description dictionary
color::table [dict]
color::table
replaces descriptions found in an
associative array by corresponding ASCII 8-color codes. The
dict can subsequently be used as a
lookup table
.
The descriptions must be written for
color::encode(1)
.
If there is a type mismatch or if dict is undefined,
color::table
panics by calling fatal(1)
.
color::table
returns with an exit code of zero upon
successful encoding. It errors with exit status
E_PARAM_ERR/9
otherwise. The content of the original dict
is undefined in the later case.
$ declare -A COLPAL=( # color palette
[panic]='underlined blinking bold white text red background'
[alert]='bold white text red background'
[crit]='underlined bold red text'
[fatal]='bold red text'
[error]='red text'
[warn]='yellow text'
[note]='blue text'
[info]='green text'
[debug]='magenta text'
[reset]='reset'
)
$ color::table COLPAL
$ echo "${COLPAL[panic]}"
\x1b[4;5;1;37;41m
color::encode(1)
, error(1)
,
fatal(1)
breakpoint - set an intentional pausing place for debugging purpose
breakpoint
When used in conjunction of errcode::trap breakpoint
mode or if $DEBUG
is set beforehand,
breakpoint
pauses the script and throws a minimal console
to /dev/tty
. Otherwise, breakpoint
is a
no-op.
$ errcode::trap breakpoint
$ breakpoint
# breakpoint (0)
debug>
errcode::trap(1)
errcode::trap - get or set errcode
mode
errcode::trap [command]
command is one of default
| enable
| disable
| breakpoint
| status
.
If no command is given, it defaults to status
.
errcode::trap
panics by calling fatal(1)
otherwise.
errcode::trap
returns with an exit code of zero if a
errcode
is enabled, >0 otherwise.
Disabling errcode
trap
is strongly
discouraged as it may result in non obvious bad script side
effects.
$ errcode::trap \
&& echo "errcode trap is enabled" \
|| resume echo "errcode is disabled"
errcode is enabled
breakpoint(1)
error::class - error classifying tool
error::class error
With error either a positive integer in range [0-255] or a valid name:
^E_([A-Z1-9]+)((_([A-Z1-9])+)*)$
range | names | owner | note |
---|---|---|---|
0-3 | E_SUCCESS - E_UNSUPPORTED | bash | |
4-7 | N/A | unused | |
8-32 | E_BASHKIT - E_CUSTOM | bashkit | highest bit is 3 or 4 |
33-123 | custom names | user | highest bit is 5 or 6 but lesser than 124 |
124-128 | E_TIMEOUT - E_INVALID_EXIT | bash | |
129-192 | E_SIGHUP - E_SIGRTMAX | signal | highest bit is 7 low bits for signum |
193-254 | N/A | unused | |
255 | E_OUT_OF_RANGE | bash |
The queried error class is printed on stdout
and stored in special variable $__
.
error::class
returns 0 on success >0 otherwise.
$ error::class 129
signal
$ error::class E_SIGHUP
signal
error::custom(1)
, error::list(1)
,
error::whatis(1)
error::custom - register a custom error
error::custom rawname rawcode
With rawname a string and rawcode a positive
integer in range [1-90], error::custom
registers
$E_<RAWerror::custom>
wich equals
$E_CUSTOM
+ rawcode.
rawname is valid if it matches:
^E_([A-Z1-9]+)((_([A-Z1-9])+)*)$
error::custom
returns 0 if successful. It returns
$E_PARAM_ERR
when rawname or rawcode are
already defined or if rawcode is out of range.
$ error::custom empty_buffer 1
$ echo "${__}"
E_EMPTY_BUFFER=33
$ echo ${E_EMPTY_BUFFER}
33
error::class(1)
, error::list(1)
,
error::whatis(1)
error::list - error class listing tool
error::list errclass
With errclass is one of all
| bash
| bashkit
| custom
| signal
. When
errclass is not given it defaults to all
.
error::list
panics by calling fatal(1)
otherwise.
range | names | owner | note |
---|---|---|---|
0-3 | E_SUCCESS - E_UNSUPPORTED | bash | |
4-7 | N/A | unused | |
8-32 | E_BASHKIT - E_CUSTOM | bashkit | highest bit is 3 or 4 |
33-123 | custom names | user | highest bit is 5 or 6 but lesser than 124 |
124-128 | E_TIMEOUT - E_INVALID_EXIT | bash | |
129-192 | E_SIGHUP - E_SIGRTMAX | signal | highest bit is 7 low bits for signum |
193-254 | N/A | unused | |
255 | E_OUT_OF_RANGE | bash |
The queried error list is printed on stdout
.
error::list
always returns 0 unless invoked with a bad
errclass.
$ error::list | column -t -s "="
E_SUCCESS 0
E_FAILURE 1
...
E_SIGRTMAX 192
error::class(1)
, error::custom(1)
,
error::whatis(1)
error::whatis - bidirectional mapper between error codes and names
error::whaits error
With error either a positive integer in range [0-255] or a valid name:
^E_([A-Z1-9]+)((_([A-Z1-9])+)*)$
range | names | owner | note |
---|---|---|---|
0-3 | E_SUCCESS - E_UNSUPPORTED | bash | |
4-7 | N/A | unused | |
8-32 | E_BASHKIT - E_CUSTOM | bashkit | highest bit is 3 or 4 |
33-123 | custom names | user | highest bit is 5 or 6 but lesser than 124 |
124-128 | E_TIMEOUT - E_INVALID_EXIT | bash | |
129-192 | E_SIGHUP - E_SIGRTMAX | signal | highest bit is 7 low bits for signum |
193-254 | N/A | unused | |
255 | E_OUT_OF_RANGE | bash |
The queried error code/name is printed on stdout
and stored in special variable $__
.
error::whatis
returns 0 on success >0 otherwise.
$ error::whatis 129
E_SIGHUP
$ error::class E_SIGHUP
129
error::class
, error::custom(1)
,
error::list(1)
alert - display an alert message
alert [message …]
With message a string, alert
takes an arbitrary
number of message arguments. message can be set in
special variable $__
or by calling
raise(1)
.
If $LOGLEVEL
is >= 1 beforehand or set at runtime
each message argument is displayed on its own.
alert
is an errcode
handler, it returns
previous $?
unless a write or assignment error occurs.
$ alert
2022-11-07 16:50:12+0100 [alert] bash:1|
$ alert "alert message"
2022-11-07 16:50:14+0100 [alert] bash:1| alert message
$ __='preset error'; false \
|| alert
2022-11-07 16:52:11+0100 [alert] bash:1| preset error
$ false || alert 'failure!'
2022-11-07 16:53:44+0100 [alert] bash:1| failure!
$ false \
|| raise "${E_PARAM_ERR}" 'not good' \
|| alert
2022-11-07 16:59:33+0100 [alert] bash:1| not good
logging::level(1)
, logging::setlevel(1)
,
errcode::trap(1)
, raise(1)
crit - display a critical message
crit [message …]
With message a string, crit
takes an arbitrary
number of message arguments. message can be set in
special variable $__
or by calling
raise(1)
.
If $LOGLEVEL
is >= 2 beforehand or set at runtime
each message argument is displayed on its own.
crit
is an errcode
handler, it returns
previous $?
unless a write or assignment error occurs.
$ crit
2022-11-07 16:50:12+0100 [crit] bash:1|
$ crit "crit message"
2022-11-07 16:50:14+0100 [crit] bash:1| crit message
$ __='preset error'; false \
|| crit
2022-11-07 16:52:11+0100 [crit] bash:1| preset error
$ false || crit 'failure!'
2022-11-07 16:53:44+0100 [crit] bash:1| failure!
$ false \
|| raise "${E_PARAM_ERR}" 'not good' \
|| crit
2022-11-07 16:59:33+0100 [crit] bash:1| not good
logging::level(1)
, logging::setlevel(1)
,
errcode::trap(1)
, raise(1)
debug - display a debugging message
debug [message …]
With message a string, debug
takes an arbitrary
number of message arguments. message can be set in
special variable $__
.
If $LOGLEVEL
is set to 7 beforehand or at runtime each
message is displayed on its own.
When $TRACE
or $REPORT
are set,
$LOGLEVEL
defaults to 7
debug
returns success unless a write or assignment error
occurs.
$ debug
2022-11-08 00:59:32+0100 [debug] bash:1|
$ debug "debug message"
2022-11-08 01:00:03+0100 [debug] bash:1| debug message
$ __='preset message' && debug
2022-11-08 01:00:57+0100 [debug] bash:1| preset message
logging::level(1)
, logging::setlevel(1)
error - display an error message
error [message …]
With message a string, error
takes an arbitrary
number of message arguments. message can be set in
special variable $__
or by calling
raise(1)
.
If $LOGLEVEL
is >= 3 beforehand or set during runtime
each message is displayed on its own.
error
is an errcode
handler, it returns
previous $?
unless a write or assignment error occurs.
$ error
2022-11-07 16:50:12+0100 [error] bash:1|
$ error "error message"
2022-11-07 16:50:14+0100 [error] bash:1| error message
$ __='preset error'; false \
|| error
2022-11-07 16:52:11+0100 [error] bash:1| preset error
$ false || error 'failure!'
2022-11-07 16:53:44+0100 [error] bash:1| failure!
$ false \
|| raise "${E_PARAM_ERR}" 'not good' \
|| error
2022-11-07 16:59:33+0100 [error] bash:1| not good
logging::level(1)
, logging::setlevel(1)
,
errcode::trap(1)
, raise(1)
fatal - display a message and panic with an error code
fatal [message …]
With message a string, fatal
takes an arbitrary
number of message arguments. message can be set in
special variable $__
or by calling
raise(1)
.
Each message is always displayed on its own.
fatal
is an errcode
handler, it returns
previous $?
unless a write or assignment error occurs. If
previous $?
is 0, fatal
defaults to 1.
$ fatal
2022-11-07 16:50:12+0100 [fatal] bash:1|
$ fatal "fatal message"
2022-11-07 16:50:14+0100 [fatal] bash:1| fatal message
$ __='preset fatal'; false \
|| fatal
2022-11-07 16:52:11+0100 [fatal] bash:1| preset fatal
$ false || fatal 'failure!'
2022-11-07 16:53:44+0100 [fatal] bash:1| failure!
$ false \
|| raise "${E_PARAM_ERR}" 'not good' \
|| fatal
2022-11-07 16:59:33+0100 [fatal] bash:1| not good
logging::level(1)
, logging::setlevel(1)
,
errcode::trap(1)
, raise(1)
info - display an informational message
info [message …]
With message a string, info
takes an arbitrary
number of message arguments. message can be set in
special variable $__
.
If $LOGLEVEL
is >= 6 beforehand or set at runtime
each message is displayed on its own.
info
returns success unless a write or assignment error
occurs.
info
shadows info(1)
the bash info document
reader. If you need to use this reader, invoke it with
command
info
.
$ info
2022-11-08 00:59:32+0100 [info] bash:1|
$ info "info message"
2022-11-08 01:00:03+0100 [info] bash:1| info message
$ __='preset message' && info
2022-11-08 01:00:57+0100 [info] bash:1| preset message
logging::level(1)
, logging::setlevel(1)
for info(1)
disambiguation:
builtin command
, info(1)
$ command [-pVv] info [arg ...]
logging::level - display the current logging level
logging::level
logging::level
displays the current script logging level
on stdout
.
It returns success unless a write or assignment error occurs.
$ logging::level
6
logging::setlevel(1)
note - display a note message
note [message …]
With message a string, note
takes an arbitrary
number of message arguments. message can be set in
special variable $__
.
If $LOGLEVEL
is >= 5 beforehand or set at runtime
each message is displayed on its own.
note
returns success unless a write or assignment error
occurs.
$ note
2022-11-08 00:59:32+0100 [note] bash:1|
$ note "note message"
2022-11-08 01:00:03+0100 [note] bash:1| note message
$ __='preset message' && note
2022-11-08 01:00:57+0100 [note] bash:1| preset message
logging::level(1)
, logging::setlevel(1)
panic - display a message and panic with error code 1
panic [message …]
With message a string, panic
takes an arbitrary
number of message arguments. message can be set in
special variable $__
or by calling
raise(1)
.
Each message is always displayed on its own.
panic
is an errcode
handler, it returns
1.
$ panic
2022-11-07 16:50:12+0100 [panic] bash:1|
$ panic "panic message"
2022-11-07 16:50:14+0100 [panic] bash:1| panic message
$ __='preset panic'; false \
|| panic
2022-11-07 16:52:11+0100 [panic] bash:1| preset panic
$ false || panic 'failure!'
2022-11-07 16:53:44+0100 [panic] bash:1| failure!
$ false \
|| raise "${E_PARAM_ERR}" 'not good' \
|| panic
2022-11-07 16:59:33+0100 [panic] bash:1| not good
logging::level(1)
, logging::setlevel(1)
,
errcode::trap(1)
, raise(1)
logging::setlevel - modify the current logging level
logging::setlevel [level]
With level either an integer in [0-7] or a string in: panic
| emerg | alert | crit | error | warn | note | info | debug,
logging::setlevel
sets the current script logging
level.
If level is invalid, the logging level defaults to INFO/6.
logging::setlevel
returns success.
$ logging::setlevel 7
$ logging::setlevel debug
logging::level(1)
warn - display a warn message
warn [message …]
With message a string, warn
takes an arbitrary
number of message arguments. message can be set in
special variable $__
.
If $LOGLEVEL
is >= 4 beforehand or set at runtime
each message is displayed on its own.
warn
returns success unless a write or assignment error
occurs.
$ warn
2022-11-08 00:59:32+0100 [warn] bash:1|
$ warn "warn message"
2022-11-08 01:00:03+0100 [warn] bash:1| warn message
$ __='preset message' && warn
2022-11-08 01:00:57+0100 [warn] bash:1| preset message
logging::level(1)
, logging::setlevel(1)
trap::callback - hook a command to a signal
trap::callback [[arg] signal_spec …]
trap::callback
is a wrapper to bash builtin trap that
goes the extra mile of stacking up arg to already hooked up
commands.
arg and signal_spec are defined in builtin
trap
help.
Upon reception of signal_spec, the commands are executed in LIFO order.
$ trap::callback "echo goodbye world!" EXIT
goodbye world!
builtin trap
, cleanup(1)
cleanup - hook a command to the EXIT signal
cleanup [arg]
cleanup
is a wrapper to bashkit
trap::callback
on the EXIT signal.
arg is defined in bash builtin trap help.
Upon reception of EXIT, the commands are executed in LIFO order.
$ cleanup "echo goodbye world!"
goodbye world!
$ touch /tmp/tmpfile && cleanup 'rm -f /tmp/tmpfile'
builtin trap
, trap::callback(1)
version::bashkit - get current bashkit version
version::bashkit [VAR]
The version is stored in special bashkit variable $__
or
in $VAR
if present.
version::bashkit
creates a semver compatible version
string in the form compat.date.commit[.branch][.hash]
.
compat
compatibility, is changed in case of breaking
changesdate
month and year release date, inform on available
featurescommit
unique version numberbranch
only if not default, which branch was used to
release bashkithash
only if local files changed, see
state(1)
$ version::bashkit && echo "${__}"
1.2210.230
version::state(1)
This page is part of the wuage bashkit framework. Source code and all documentation maybe downloaded from http://bashkit.wuage.org
The doc
directory distributed with bashkit
contains full documentation.
version::state - get local bashkit version state
version::state [VAR]
The state is stored in special bashkit variable $__
or
in $VAR
if present.
version::state
outputs a string containing local files
version information, and is the input of hash
version field
see version::bashkit(1)
.
version::state
outputs nothing if local files are not
modified.
$ version::state && echo "${__}"
changed_version.bash ...
version::bashkit(1)
This page is part of the wuage bashkit framework. Source code and all documentation maybe downloaded from http://bashkit.wuage.org
The doc
directory distributed with bashkit
contains full documentation.
version::update - set current bashkit version
version::update
version::update
is intended to be used by bashkit
developers, it allows updating version.bash
with current
version informations.
version::update
generates values for both
version::bashkit(1)
and version::state(1)
.
$ version::update
version::bashkit(1)
version::state(1)
This page is part of the wuage bashkit framework. Source code and all documentation maybe downloaded from http://bashkit.wuage.org
The doc
directory distributed with bashkit
contains full documentation.
array::contains - test if an array contains a given value
array::contains A x [idx]
With A an array variable, x a value and
idx a variable, array::contains
test if x
exists in A and set idx to x index. If
idx is not given, the index is set in special variable
$__
.
array::contains
returns 0 if x in A,
>0 otherwise or if an error occurs.
$ declare -a ARRAY=( 1 2 3 4 )
$ array::contains ARRAY 2 idx
$ echo $?
0
$ echo "${ARRAY[idx]}"
2
array::inter - intersect two arrays
array::inter A B
With A et B array variables,
array::inter
intersects A and B and set
the resulting array in A.
array::inter
returns 0 unless wrong arguments or error
>0.
$ declare -a A=( hello world 1 2 3 4 )
$ declare -a B=( 3 4 5 6 goodbye world )
$ array::inter A B
$ echo "${A[@]}"
3 4 world
array::map - apply a function to an array elements
array::map A fun
With A an array variable and fun a bash function
that transforms $1
and prints the result to
stdout
, array::map
applies fun in
place to each elements of A.
array::map
returns 0 upon success >0 otherwise.
$ declare -a A=( {a..e} )
$ up(){ echo ${1^^}; }
$ array::map A up
$ echo "${A[@]}"
A B C D E
array::reduce(1)
array::pick - pick a random array element
array::pick A [x]
With A an array variable and x a variable,
array::pick
sets x to a random element of
A. If x is not specified, it defaults to the special
variable $__
.
array::pick
returns 0 upon success, >0 otherwise.
$ declare -a A=( 1 2 3 4 )
$ array::pick A x
$ echo "${x}"
3
array::pop - remove the last element from an array
array::pop A [x]
With A an array variable and x a variable,
array::pop
sets x to the last element from
A before removing it. If x is not specified, it
defaults to the special variable $__
.
array::pop
returns 0 upon success, >0 otherwise.
$ declare -a A=( 1 2 3 4 )
$ array::pop A x
$ echo "${A[@]}"
1 2 3
$ echo "${x}"
4
array::popi(1)
array::popi - remove the ith element from an array
array::popi A i [x]
With A an array variable i an index and x
a variable, array::popi
sets x to the ith element
from A before removing it. If i is negative, the
element is removed starting from the end of A. If x is
not specified, it defaults to the special variable $__
.
array::popi
returns 0 upon success, >0 otherwise.
$ declare -a A=( 1 2 3 4 )
$ array::popi A 2 x
$ echo "${A[@]}"
1 2 4
$ echo "${x}"
3
array::pop(1)
, array::shift(1)
array::push - add one or more elements to the end of an array
array::push A [x …]
With A an array variable x a value,
array::push
adds x at the end of A.
array::push
returns 0 upon success, >0 otherwise.
$ declare -a A=( {1..11} )
$ array::push A 12
$ echo "${A[-1]}"
12
array::reduce - perform a summary operation of an array
array::reduce A fun acc
With A an array variable, fun a bash function that
aggregates $1
and $2
and prints the result to
stdout
and acc a variable,
array::reduce
sumarizes A into acc by
repetitively aplying fun acc x
for x in
A.
array::reduce
returns 0 upon success, >0
otherwise.
$ declare -a A=( {1..8} )
$ add() { echo $(( $1 + $2 )); }
$ acc=0
$ array::reduce A add acc
$ echo "${acc}"
36
array::map(1)
array::reverse - reverse an array in place
array::reverse A
With A an array variable, array::reverse
reverses A in place.
array::reverse
returns 0 upon success, >0
otherwise.
$ declare -a A=( {1..11} )
$ array::reverse A
$ echo "${A[@]}"
11 10 9 8 7 6 5 4 3 2 1
array::rotate - shift elements of an array to the specified positions
array::rotate A i
With A an array variable and i an integer,
array::rotate
shifts elements of A to the
specified positions. If i is positive, cycling is done from
right to left, if i is negative, cycling occurs from left to
right.
array::rotate
returns 0 upon success, >0
otherwise.
$ declare -a A=( {1..8} )
$ array::rotate A -10
$ echo "${A[@]}"
3 4 5 6 7 8 1 2
array::shift - remove the first element of an array
array::shift A [x]
With A an array variable and x a variable,
array::shift
removes the first element of A and
sets x to it. If x is not given, it defaults to
special variable $__
.
array::shift
returns 0 upon success, >0
otherwise.
$ declare -a A=( {1..8} )
$ array::shift A x
$ (( x == 1 )) && echo "${A[@]}"
2 3 4 5 6 7 8
array::popi(1)
array::shuffle - randomly reorder elements of an array
array::shuffle A
With A an array variable, array::shuffle
performs in place a modern fisher-yates shuffling.
array::shuffle
returns 0 upon success, >0
otherwise.
$ declare -a A=( {1..8} )
$ array::shuffle A
$ echo "${A[@]}"
7 6 2 1 3 4 5 8
https://en.wikipedia.org/wiki/Fisher–Yates_shuffle#Modern_method
array::sort - sort elements of an array in place
array::sort A
With A an array variable, array::sort
in place
sorts the array.
array::sort
returns 0 upon success, >0 otherwise.
$ declare -a A=( 8 7 5 6 3 4 1 2 )
$ array::sort A
$ echo "${A[@]}"
1 2 3 4 5 6 7 8
array::split - build an array from a split string
array::split A str sep
With A an array variable, str and sep two
strings, array::split
divides str into an ordered
list of substrings by searching for sep, puts these substrings
in A.
array::split
returns 0 upon success, >0
otherwise.
$ declare -a A
$ array::split A 'apples,oranges,pears,grapes' ','
$ echo "${A[@]}"
apples oranges pears grapes
array::uniq - deduplicate elements of an array
array::uniq A
With A an array variable, array:uniq
deduplicates elements in place.
array::uniq
returns 0 upon success, >0 otherwise.
$ declare -a A=( {1..8} )
$ A+=( "${A[@]}" ) # duplicate array items
$ echo "${A[@]}"
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
$ array::uniq A
$ echo "${A[@]}"
1 2 3 4 5 6 7 8
array::unshift - add one or more elements to the beginning of an array
array::unshift A [x …]
With A an array variable and a list of values x,
array::unshift
adds them to the beginning of A
array::unshift
returns 0 upon success, >0
otherwise.
$ declare -a A=( {4..8} )
$ array::unshift A 1 2 3
$ echo "${A[@]}"
1 2 3 4 5 6 7 8
array::zip - merge two arrays in a dictionary
array::zip D K V
With D an dictionary (ie. associative array), K and
V two arrays, array::zip
merges the arrays into a
dict where keys are taken from K ans associated to values taken
in turn from V.
array::zip
returns 0 upon success, >0 otherwise.
$ declare -A D
$ declare -a K=( {a..e} )
$ declare -a V=( {1..8} )
$ array::zip D K V
$ declare -p D
D=([e]="5" [d]="4" [c]="3" [b]="2" [a]="1" )
check::cmd - check if a command is available
check::cmd [cmd …]
With a list of cmd, check::cmd
verify that
cmd is executable.
check::cmd
returns 0 if cmd is executable,
>0 otherwise.
$ check::cmd ls cat && echo "ls and cat are available"
ls and cat are available
check::dir - ensure a directory exists
check::dir [dir …]
With dir a directory, check::dir
ensures that
it exists, if not it creates it.
check::dir
returns 0 if dir exists or has been
created, >0 otherwise.
$ check::dir /usr /tmp/mydir
check::vartype - check variable attributes
check::vartype attrs var
With attrs an attribute string and var a variable,
check::vartype
checks if var has set
attrs. It does NOT check the content of var.
Some attrs are inherited from builtin
declare
:
attr | description |
---|---|
a | indexed array |
A | dictionary |
i | integer |
l | lower case |
n | nameref |
r | readonly |
t | trace |
u | upper case |
x | export |
to which bashkit adds:
attr | description |
---|---|
f | function |
s | set |
A var can be set to an empty value. When checking for a nameref and more, var is dereferenced before checking for more attrs than n.
check::vartype
returns 0 upon success, >0
otherwise.
$ declare -a ARR=()
$ declare -n _A=ARR
$ check::vartype nas _A && echo OK
OK
$ n=0 # no integer attribute
$ check::vartype i n || echo NOK
NOK
builtin declare
curl::download - download a file from an URL and print stats
curl::download url dest
With dest being a filename, curl::download
prints a downloading digest that contains the size and md5 hash of the
downloaded file.
In baskhit, curl
hence curl::download
are
preset with: | option | value | |—————–|——-| | connect-timeout | 5 | |
continue-at | - | | fail | | | location | | | retry | 5 | | retry-delay
| 0 | | retry-max-time | 40 | | show-error | | | silent | |
curl::download
returns 0 upon success, >0
otherwise.
$ curl::download http://example.com "${tmpfile}"
curl(1)
funlist - list all declared functions
funlist
funlist
is part of bashkit module extras, it lists all
declared functions by the time of calling.
$ funlist
__unhandled
alert
bashkit::help
bashkit::init
bashkit::load
bashkit::main
...
isint - test for integers
isint [x …]
isint
is part of bashkit module extras
,
given x a value, it tests if x is an integer.
isint
returns 0 if all x are integers, >0
otherwise.
$ n=10
$ isint "${n}" 1 2 3 4 || echo yes
$ yes
join - build a string of arguments separated by a given character
join sep arg [arg …]
join
is part of bashkit module extras
,
given sep a single character and arg a list of
arbitrary strings, it builds a string with all args separated
by sep.
$ join "," a b c d
a,b,c,d
$ join ":" a
a
now - get the number of milliseconds elapsed since EPOCH
now [dest]
now
is part of bashkit module extras
, it
sets dest var to the number of milliseconds elapsed since
EPOCH. If dest is omitted, now
sets the special
variable $__
.
$ now start
$ sleep 1
$ now end
$ echo $(( end - start ))
1008
progress - display a progress bar
progress percent total
progress
is part of bashkit module extras
,
given two integers percent and total, it displays a
progress bar. This bar has a len of total dashes.
$ for (( i=0; i<=100; i++ )); do
> usleep 5
> progress "${i}" 20
> done
> printf '\n'
[--------------------]
urldecode - percent decode a string
urldecode url
urldecode
is part of bashkit module extras
,
given a percent-encoded url, it restores it to its original
form.
urldecode
returns 0 upon success, >0 otherwise.
$ urldecode "https%3A%2F%2Fgithub.com%2Fdylanaraps%2Fpure-bash-bible"
https://github.com/dylanaraps/pure-bash-bible
urlencode(1)
urlencode - percent encode a string
urlencode url
urlencode
is part of bashkit module extras
,
given an url string, it displays a percent encoded version of
it.
urlencode
returns 0 upon success, >0 otherwise.
$ urlencode "https://github.com/dylanaraps/pure-bash-bible"
https%3A%2F%2Fgithub.com%2Fdylanaraps%2Fpure-bash-bible
urldecode(1)
usleep - micro sleep
usleep [n]
usleep
is part of bashkit module extras
, it
waits for a delay proportional to n. When n is
omitted, it defaults to 1.
$ usleep 10
interactive::yesno - ask a yes/no question to the user
interactive::yesno question [default]
interactive::yesno
displays question and wait
for the user to answer, if default is given, it is used if the
user simply presses ENTER
.
interactive::yesno
returns 0 when user answers
yes
, >0 otherwise
$ interactive::yesno "are you happy?" y
are you happy? [YES/no]:
json::from_toml - convert toml to json
json::from_toml toml
Given a toml string, json::from_toml
converts
it to JSON.
json::from_toml
returns 0 upon success, >0
otherwise.
json::to_toml(1)
json::from_yaml - convert yaml to json
json::from_yaml yaml
Given a yaml string, json::from_yaml
converts
it to json.
json::from_yaml
returns 0 upon success, >0
otherwise.
json::to_yaml(1)
json::into_array - load a json array into a bash array
json::into_array A jarr
With A an array variable and jarr a string
representing a json array, json::into_array
loads
jarr content into A.
json::into_array
returns 0 upon success, >0
otherwise.
$ json='["a", "b", 3, 7]'
$ declare -a A
$ json::into_array A <<< "${json}"
$ echo "${A[@]}"
a b 3 7
json::into_dict(1)
json::into_dict - load a json dictionary into a bash one
json::into_dict D jdict
With D an associative array variable and jdict a
json dictionary, json::into_dict
loads jdict
content into D. It does NOT recurse because bash does not
support nested dictionaries.
json::into_dict
returns 0 upon success, >0
otherwise.
$ json='{"a": 3, "7": { "sub": [3, true, "x"] }}'
$ declare -A D
$ json::into_dict D <<< "${json}"
$ echo "${!D[@]}
a 7
$ echo "${D[7]}"
{ "sub": [3, true, "x"] }
json::into_array(1)
json::to_toml - convert json to toml
json::to_toml fd
With fd a file descriptor, json::to_toml
reads
json from fd and prints the resulting toml to
stdout
.
json::to_toml
returns 0 upon success, >0
otherwise.
$ printf '%s\n' "${json}" | json::to_toml /dev/stdin
json::from_toml(1)
json::to_yaml - convert json to toml
json::to_yaml fd
With fd a file descriptor, json::to_yaml
reads
json from fd and prints the resulting yaml to
stdout
.
json::to_yaml
returns 0 upon success, >0
otherwise.
$ printf '%s\n' "${json}" | json::to_yaml /dev/stdin
json::from_yaml(1)
patch::apply - apply a patch
patch::apply dir patch
Witn dir a destination directory and patch a patch
file, patch::apply
applies modification from patch
to dir files.
patch::apply
returns 0 upon success, >0
otherwise.
$ patch::apply "${DIR}" "a.patch"
diff(1)
, patch(1)
,
patch::batch(1)
patch::batch - apply all patches from a patch directory onto files in a target directory
patch::batch target patches
Witn target a destination directory and patches a
patch directory, patch::batch
applies modification from
patches to target files.
patch::batch
returns 0 upon success, >0
otherwise.
$ patch::batch "${TARGET_DIR}" "${PATCH_DIR}"
diff(1)
, patch(1)
,
patch::apply(1)
perms::gid - convert group name to gid
perms::gid group
With group a group name as given by id -g
,
perms::gid
converts it to a gid integer as given by
id -gn
.
perms::gid
returns 0 upon success, >0 and logs an
error otherwise.
$ perms::gid wheel
0
id(1)
, perms::uid(1)
perms::mode - convert symbolic file mode to absolute notation
perms::mode mode
With mode an absolute mode as defined in
chmod(1)
, perms::mode
convert it to its
absolute representation.
perms::mode
returns 0 upon success, >0 otherwise.
$ perms::mode "-rw-r--r--"
0644
chmod(1)
perms::uid - convert user name to uid
perms::uid user
With user a user name as given by id -u
,
perms::uid
converts it to an uid integer as given by
id -un
.
perms::uid
returns 0 upon success, >0 and logs an
error otherwise.
$ perms::uid root
0
id(1)
, perms::gid(1)
readlinkf - display symbolic link target status
readlinkf filelink
With filelink a symbolic link, readlinkf
resolves paths and displays the corresponding absolute pathname.
readlinkf
returns 0 upon success, >0 otherwise.
readlink(1)
, https://github.com/ko1nksm/readlinkf
shopt::pop - restores previous shopt context
shopt::pop
shopt::pop
restores a builtin shopt
context
previously created by calling shopt::push(1)
.
shopt::pop
always succeeds and returns 0.
$ shopt::push
$ shopt -s extdebug
$ do_something_with_extdebug_on
$ shopt::pop
builtin shopt
, shopt::push(1)
shopt::push - create a new shopt context
shopt::push
shopt::push
creates a new shopt
context
that can be modified and discarded later by a call to
shopt::pop(1)
.
shopt::push
always succeeds and returns 0.
$ shopt::push
$ shopt -s extdebug
$ do_something_with_extdebug_on
$ shopt::pop
builtin shopt
, shopt::push(1)
string::lstrip - remove pattern from start of string
string::lstrip str pat
With str and pat two strings,
string::lstrip
removes pat occuring at
str start (or left side).
$ string::lstrip 'The Quick Brown Fox' 'The '
Quick Brown Fox
string::rstrip(1)
, string::strip(1)
,
string::stripall(1)
string::regex - match string against regular expression
string::regex str rex
With str and rex two strings,
string::regex
matches str again regular expression
rex and displays the matching part of str.
string::regex
returns 0 upon match, >0 otherwise.
$ string::regex ' hello' '^[[:space:]]*(.*)'
hello
string::rstrip - remove pattern from end of string
string::rstrip str pat
With str and pat two strings,
string::rstrip
removes pat occuring at
str end (or right side).
$ string::rstrip 'The Quick Brown Fox' ' Fox'
The Quick Brown
string::lstrip(1)
, string::strip(1)
,
string::stripall(1)
string::split - extract substrings delimited by a separator from string
string::split str sep
With str and sep, two strings,
string::split
splits str on sep
occurences.
$ string::split 'apples,oranges,pears,grapes' ','
apples oranges pears grapes
string::strip - remove first occuring pattern from string
string::strip str pat
With str and pat two strings,
string::strip
removes the first occurence of pat
in str.
$ string::strip 'The Quick Brown Fox' '[aeiou]'
Th Quick Brown Fox
string::stripall(1)
, string::lstrip(1)
,
string::rstrip(1)
string::stripall - remove pattern from string
string::stripall str pat
With str and pat two strings,
string::stripall
removes all occurences of pat in
str.
$ string::strip 'The Quick Brown Fox' '[aeiou]'
Th Quck Brwn Fx
string::strip(1)
, string::lstrip(1)
,
string::rstrip(1)
string::trim - remove leadind and trailing spaces from string
string::trim str
string::trim
removes all leading and trailing spaces
from string str.
$ string::trim ’ Hello, world ’ Hello, world
semver::compare - compare two semantic version strings and return the result
semver::compare [V1] [V2]
semver::compare
compares two semantic version strings,
V1 and V2, and returns the result in the form of an integer.
The comparison result is stored in the variable __
. A
value of 0 indicates that the input strings are equal, a value of 1
indicates that the first input string is greater than the second input
string, and a value of -1 indicates that the first input string is less
than the second input string.
$ semver::compare "1.2.3-alpha.1+build.42" "1.2.3-beta.1+build.42"
$ echo "${__}" # output: -1
semver::parse - parse a semantic version string and return major, minor, patch, pre-release, and build information
semver::parse [string]
semver::parse
parses a semantic version string and
returns major, minor, patch, pre-release, and build information. The
input string must be in the format of “X.Y.Z(-PRERELEASE)(+BUILD)”. The
function checks the input string against a regular expression to ensure
the proper format. If the input string does not match the format, the
function raises an error. The returned information is stored in
__
, with the following elements:
${__[0]} - major version
${__[1]} - minor version
${__[2]} - patch version
${__[3]} - pre-release version
${__[4]} - build version
$ semver::parse "v1.2.3-alpha.1+build.42"
$ echo "${__[0]}" # output: 1
$ echo "${__[3]}" # output: alpha.1