Developing in bash has some serious flaws:
./doc_test.sh array.sh -v
./doc_test.sh
./doc_test.sh -v
Source the core module and use core.import
to import other modules.
#!/usr/bin/env bash source path/to/core.sh core.import <modulename> core.import <another modulename> # use modules ...
Currently only an archlinux package is available at the aur. After installation all rebash files are available under /usr/lib/rebash/
. The doc_test and documentation modules are available as /usr/bin/rebash-doc-test
and /usr/bin/rebash-documentation
.
Modules are single files. The function core.import guarantees that each module is sourced only once. All variables and functions defined inside a module should be prefixed with the module name. E.g. core_import
for the function import
in module core
. Aliases inside the module are used to define public functions and to have a convinient way to distinguish the module namespace from the function (alias core.import="core_import"
).
A typical minimal module looks like this (with filename mockup.sh
):
#!/usr/bin/env bash source "$(dirname "${BASH_SOURCE[0]}")/core.sh" core.import logging mockup_foo() { echo foo } alias mockup.foo="mockup_foo"Best practices / coding style
Loading modules (i.e. when sourced by the import mechanism) should be side-effect free, so only variable and function definitions should be made at the module level. If the module should be executable, use core.is_main. For example this module does activate exceptions only when run directly, not when being sourced.
#!/usr/bin/env bash source path/to/core.sh core.import exceptions main() { exceptions.activate # do stuff } if core.is_main; then main fi
Write doc_tests for every module and function. Write the tests before writing the implementation.
Use shellcheck to tackle common errors and pitfalls in bash.
The arguments module provides an argument parser that can be used in functions and scripts.
Different functions are provided in order to parse an arguments array.
>>> _() { >>> local value >>> arguments.set "$@" >>> arguments.get_parameter param1 value >>> echo "param1: $value" >>> arguments.get_keyword keyword2 value >>> echo "keyword2: $value" >>> arguments.get_flag --flag4 value >>> echo "--flag4: $value" >>> # NOTE: Get the positionals last >>> arguments.get_positional 1 value >>> echo 1: "$value" >>> # Alternative way to get positionals: Set the arguments array to >>> # $arguments_new_arguments >>> set -- "${arguments_new_arguments[@]}" >>> echo 1: "$1" >>> } >>> _ param1 value1 keyword2=value2 positional3 --flag4 param1: value1 keyword2: value2 --flag4: true 1: positional3 1: positional3Function arguments_get_flag
arguments.get_flag flag [flag_aliases...] variable_name
Sets variable_name
to true if flag (or on of its aliases) is contained in the argument array (see arguments.set
)
arguments.get_flag verbose --verbose -v verbose_is_set
>>> arguments.set other_param1 --foo other_param2 >>> local foo bar >>> arguments.get_flag --foo -f foo >>> echo $foo >>> arguments.get_flag --bar bar >>> echo $bar >>> echo "${arguments_new_arguments[@]}" true false other_param1 other_param2
>>> arguments.set -f >>> local foo >>> arguments.get_flag --foo -f foo >>> echo $foo trueFunction arguments_get_keyword
arguments.get_keyword keyword variable_name
Sets variable_name
to the "value" of keyword
the argument array (see arguments.set
) contains "keyword=value".
arguments.get_keyword log loglevel
>>> local foo >>> arguments.set other_param1 foo=bar baz=baz other_param2 >>> arguments.get_keyword foo foo >>> echo $foo >>> echo "${arguments_new_arguments[@]}" bar other_param1 baz=baz other_param2
>>> local foo >>> arguments.set other_param1 foo=bar baz=baz other_param2 >>> arguments.get_keyword foo >>> echo $foo >>> arguments.get_keyword baz foo >>> echo $foo bar bazFunction arguments_get_parameter
arguments.get_parameter parameter [parameter_aliases...] variable_name
Sets variable_name
to the field following parameter
(or one of the parameter_aliases
) from the argument array (see arguments.set
).
arguments.get_parameter --log-level -l loglevel
>>> local foo >>> arguments.set other_param1 --foo bar other_param2 >>> arguments.get_parameter --foo -f foo >>> echo $foo >>> echo "${arguments_new_arguments[@]}" bar other_param1 other_param2Function arguments_get_positional
arguments.get_positional index variable_name
Get the positional parameter at index
. Use after extracting parameters, keywords and flags.
>>> arguments.set parameter foo --flag pos1 pos2 --keyword=foo >>> arguments.get_flag --flag _ >>> arguments.get_parameter parameter _ >>> arguments.get_keyword --keyword _ >>> local positional1 positional2 >>> arguments.get_positional 1 positional1 >>> arguments.get_positional 2 positional2 >>> echo "$positional1 $positional2" pos1 pos2
arguments.set argument1 argument2 ...
Set the array the arguments-module is working on. After getting the desired arguments, the new argument array can be accessed via arguments_new_arguments
. This new array contains all remaining arguments.
Filters values from given array by given regular expression.
>>> local a=(one two three wolf) >>> local b=( $(array.filter ".*wo.*" "${a[@]}") ) >>> echo ${b[*]} two wolf
Get index of value in an array
>>> local a=(one two three) >>> array_get_index one "${a[@]}" 0
>>> local a=(one two three) >>> array_get_index two "${a[@]}" 1
>>> array_get_index bar foo bar baz 1
Returns a slice of an array (similar to Python).
From the Python documentation: One way to remember how slices work is to think of the indices as pointing between elements, with the left edge of the first character numbered 0. Then the right edge of the last element of an array of length n has index n, for example:
+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
>>> local a=(0 1 2 3 4 5) >>> echo $(array.slice 1:-2 "${a[@]}") 1 2 3
>>> local a=(0 1 2 3 4 5) >>> echo $(array.slice 0:1 "${a[@]}") 0
>>> local a=(0 1 2 3 4 5) >>> [ -z "$(array.slice 1:1 "${a[@]}")" ] && echo empty empty
>>> local a=(0 1 2 3 4 5) >>> [ -z "$(array.slice 2:1 "${a[@]}")" ] && echo empty empty
>>> local a=(0 1 2 3 4 5) >>> [ -z "$(array.slice -2:-3 "${a[@]}")" ] && echo empty empty
>>> local a=(0 1 2 3 4 5) >>> [ -z "$(array.slice -2:-2 "${a[@]}")" ] && echo empty empty
Slice indices have useful defaults; an omitted first index defaults to zero, an omitted second index defaults to the size of the string being sliced.
>>> local a=(0 1 2 3 4 5) >>> # from the beginning to position 2 (excluded) >>> echo $(array.slice 0:2 "${a[@]}") >>> echo $(array.slice :2 "${a[@]}") 0 1 0 1
>>> local a=(0 1 2 3 4 5) >>> # from position 3 (included) to the end >>> echo $(array.slice 3:"${#a[@]}" "${a[@]}") >>> echo $(array.slice 3: "${a[@]}") 3 4 5 3 4 5
>>> local a=(0 1 2 3 4 5) >>> # from the second-last (included) to the end >>> echo $(array.slice -2:"${#a[@]}" "${a[@]}") >>> echo $(array.slice -2: "${a[@]}") 4 5 4 5
>>> local a=(0 1 2 3 4 5) >>> echo $(array.slice -4:-2 "${a[@]}") 2 3
If no range is given, it works like normal array indices.
>>> local a=(0 1 2 3 4 5) >>> echo $(array.slice -1 "${a[@]}") 5
>>> local a=(0 1 2 3 4 5) >>> echo $(array.slice -2 "${a[@]}") 4
>>> local a=(0 1 2 3 4 5) >>> echo $(array.slice 0 "${a[@]}") 0
>>> local a=(0 1 2 3 4 5) >>> echo $(array.slice 1 "${a[@]}") 1
>>> local a=(0 1 2 3 4 5) >>> array.slice 6 "${a[@]}"; echo $? 1
>>> local a=(0 1 2 3 4 5) >>> array.slice -7 "${a[@]}"; echo $? 1
This function performs a linux change root if needed and provides all kernel api filesystems in target root by using a change root interface with minimal needed rights.
change_root /new_root /usr/bin/env bash some arguments
Perform the available change root program wich needs at least rights.
change_root_with_fake_fallback /new_root /usr/bin/env bash some arguments
Performs a change root by mounting needed host locations in change root environment.
change_root_with_kernel_api /new_root /usr/bin/env bash some arguments
Returns all defined aliases in the current scope.
Function core_get_all_declared_namesReturn all declared variables and function in the current scope.
E.g. declarations="$(core.get_all_declared_names)"
IMPORTANT: Do not use core.import inside functions -> aliases do not work TODO: explain this in more detail
>>> ( >>> core.import logging >>> logging_set_level warn >>> core.import test/mockup_module-b.sh false >>> ) +doc_test_contains imported module c module "mockup_module_c" defines unprefixed name: "foo123" imported module b
Modules should be imported only once.
>>> (core.import test/mockup_module_a.sh && \ >>> core.import test/mockup_module_a.sh) imported module a
>>> ( >>> core.import test/mockup_module_a.sh false >>> echo $core_declared_functions_after_import >>> ) imported module a mockup_module_a_foo
>>> ( >>> core.import logging >>> logging_set_level warn >>> core.import test/mockup_module_c.sh false >>> echo $core_declared_functions_after_import >>> ) +doc_test_contains imported module b imported module c module "mockup_module_c" defines unprefixed name: "foo123" foo123
Tests if variable is defined (can also be empty)
>>> local foo="bar" >>> core_is_defined foo; echo $? >>> [[ -v foo ]]; echo $? 0 0
>>> local defined_but_empty="" >>> core_is_defined defined_but_empty; echo $? 0
>>> core_is_defined undefined_variable; echo $? 1
>>> set -o nounset >>> core_is_defined undefined_variable; echo $? 1
Same Tests for bash < 4.2
>>> core__bash_version_test=true >>> local foo="bar" >>> core_is_defined foo; echo $? 0
>>> core__bash_version_test=true >>> local defined_but_empty="" >>> core_is_defined defined_but_empty; echo $? 0
>>> core__bash_version_test=true >>> core_is_defined undefined_variable; echo $? 1
>>> core__bash_version_test=true >>> set -o nounset >>> core_is_defined undefined_variable; echo $? 1
Tests if variable is empty (undefined variables are not empty)
>>> local foo="bar" >>> core_is_empty foo; echo $? 1
>>> local defined_and_empty="" >>> core_is_empty defined_and_empty; echo $? 0
>>> core_is_empty undefined_variable; echo $? 1
>>> set -u >>> core_is_empty undefined_variable; echo $? 1
Returns true if current script is being executed.
>>> # Note: this test passes because is_main is called by doc_test.sh which >>> # is being executed. >>> core.is_main && echo yes yes
Computes relative path from $1 to $2. Taken from http://stackoverflow.com/a/12498485/2972353
>>> core_rel_path "/A/B/C" "/A" ../..
>>> core_rel_path "/A/B/C" "/A/B" ..
>>> core_rel_path "/A/B/C" "/A/B/C/D" D
>>> core_rel_path "/A/B/C" "/A/B/C/D/E" D/E
>>> core_rel_path "/A/B/C" "/A/B/D" ../D
>>> core_rel_path "/A/B/C" "/A/B/D/E" ../D/E
>>> core_rel_path "/A/B/C" "/A/D" ../../D
>>> core_rel_path "/A/B/C" "/A/D/E" ../../D/E
>>> core_rel_path "/A/B/C" "/D/E/F" ../../../D/E/F
>>> core_rel_path "/" "/" .
>>> core_rel_path "/A/B/C" "/A/B/C" .
>>> core_rel_path "/A/B/C" "/" ../../../Function core_source_with_namespace_check
Sources a script and checks variable definitions before and after sourcing.
>>> local foo="a b a b c b c" >>> echo -e "$foo" | core.unique a b c
Usage: variable=$(dictionary.get dictionary_name key)
>>> dictionary_get unset_map unset_value; echo $? 1
>>> dictionary__bash_version_test=true >>> dictionary_get unset_map unset_value; echo $? 1
>>> dictionary_set map foo 2 >>> dictionary_set map bar 1 >>> dictionary_get map foo >>> dictionary_get map bar 2 1
>>> dictionary_set map foo "a b c" >>> dictionary_get map foo a b c
>>> dictionary__bash_version_test=true >>> dictionary_set map foo 2 >>> dictionary_get map foo 2
>>> dictionary__bash_version_test=true >>> dictionary_set map foo "a b c" >>> dictionary_get map foo a b cFunction dictionary_get_keys
>>> dictionary_set map foo "a b c" bar 5 >>> dictionary_get_keys map bar foo
>>> dictionary__bash_version_test=true >>> dictionary_set map foo "a b c" bar 5 >>> dictionary_get_keys map | sort -u bar foo
Usage: dictionary.set dictionary_name key value
>>> dictionary_set map foo 2 >>> echo ${dictionary__store_map[foo]} 2
>>> dictionary_set map foo "a b c" bar 5 >>> echo ${dictionary__store_map[foo]} >>> echo ${dictionary__store_map[bar]} a b c 5
>>> dictionary_set map foo "a b c" bar; echo $? 1
>>> dictionary__bash_version_test=true >>> dictionary_set map foo 2 >>> echo $dictionary__store_map_foo 2
>>> dictionary__bash_version_test=true >>> dictionary_set map foo "a b c" >>> echo $dictionary__store_map_foo a b c
The doc_test module implements function and module level testing via "doc strings".
Tests can be run by invoking doc_test.sh file1 folder1 file2 ...
.
--help|-h Print help message.
--side-by-side Print diff of failing tests side by side.
--no-check-namespace Do not warn about unprefixed definitions.
--no-check-undocumented Do not warn about undocumented functions.
--use-nounset Accessing undefined variables produces error.
--verbose|-v Be more verbose
Example output ./doc_test.sh -v arguments.sh
[verbose:doc_test.sh:330] arguments:[PASS] [verbose:doc_test.sh:330] arguments_get_flag:[PASS] [verbose:doc_test.sh:330] arguments_get_keyword:[PASS] [verbose:doc_test.sh:330] arguments_get_parameter:[PASS] [verbose:doc_test.sh:330] arguments_get_positional:[PASS] [verbose:doc_test.sh:330] arguments_set:[PASS] [info:doc_test.sh:590] arguments - passed 6/6 tests in 918 ms [info:doc_test.sh:643] Total: passed 1/1 modules in 941 ms
A doc string can be defined for a function by defining a variable named __doc__
at the function scope. On the module level, the variable name should be <module_name>__doc__
(e.g. arguments__doc__
for the example above). Note: The doc string needs to be defined with single quotes.
Code contained in a module level variable named <module_name>__doc_test_setup__
will be run once before all the Tests of a module are run. This is usefull for defining mockup functions/data that can be used throughout all tests.
Tests are delimited by blank lines:
But can also occur right after another:
Single quotes can be escaped like so:
Or so
Some text in between.
Multiline output
>>> local i >>> for i in 1 2; do >>> echo $i; >>> done 1 2
Ellipsis support
>>> local i >>> for i in 1 2 3 4 5; do >>> echo $i; >>> done +doc_test_ellipsis 1 2 ...
Ellipsis are non greedy
>>> local i >>> for i in 1 2 3 4 5; do >>> echo $i; >>> done +doc_test_ellipsis 1 ... 4 5
Each testcase has its own scope:
>>> local testing="foo"; echo $testing foo
>>> [ -z "${testing:-}" ] && echo empty empty
Syntax error in testcode:
>>> f() {a} +doc_test_contains +doc_test_ellipsis syntax error near unexpected token `{a} ...Function doc_test_compare_result
>>> local buffer="line 1 >>> line 2" >>> local got="line 1 >>> line 2" >>> doc_test_compare_result "$buffer" "$got"; echo $? 0
>>> local buffer="line 1 >>> foo" >>> local got="line 1 >>> line 2" >>> doc_test_compare_result "$buffer" "$got"; echo $? 1
>>> local buffer="+doc_test_contains >>> line >>> line" >>> local got="line 1 >>> line 2" >>> doc_test_compare_result "$buffer" "$got"; echo $? 0
>>> local buffer="+doc_test_contains >>> line >>> foo" >>> local got="line 1 >>> line 2" >>> doc_test_compare_result "$buffer" "$got"; echo $? 1
>>> local buffer="+doc_test_ellipsis >>> line >>> ... >>> " >>> local got="line >>> line 2 >>> " >>> doc_test_compare_result "$buffer" "$got"; echo $? 0
>>> local buffer="+doc_test_ellipsis >>> line >>> ... >>> line 2 >>> " >>> local got="line >>> ignore >>> ignore >>> line 2 >>> " >>> doc_test_compare_result "$buffer" "$got"; echo $? 0
>>> local buffer="+doc_test_ellipsis >>> line >>> ... >>> line 2 >>> " >>> local got="line >>> ignore >>> ignore >>> line 2 >>> line 3 >>> " >>> doc_test_compare_result "$buffer" "$got"; echo $? 1
>>> local test_buffer=" >>> echo foo >>> echo bar >>> " >>> local output_buffer="foo >>> bar" >>> doc_test_use_side_by_side_output=false >>> doc_test_module_under_test=core >>> doc_test_nounset=false >>> doc_test_eval "$test_buffer" "$output_buffer"Function doc_test_parse_args Function doc_test_parse_doc_string
>>> local doc_string=" >>> (test)block >>> output block >>> " >>> _() { >>> local output_buffer="$2" >>> echo block: >>> while read -r line; do >>> if [ -z "$line" ]; then >>> echo "empty_line" >>> else >>> echo "$line" >>> fi >>> done <<< "$output_buffer" >>> } >>> doc_test_parse_doc_string "$doc_string" _ "(test)" block: output block
>>> local doc_string=" >>> Some text (block 1). >>> >>> >>> Some more text (block 1). >>> (test)block 2 >>> (test)block 2.2 >>> output block 2 >>> (test)block 3 >>> output block 3 >>> >>> Even more text (block 4). >>> " >>> local i=0 >>> _() { >>> local test_buffer="$1" >>> local output_buffer="$2" >>> local text_buffer="$3" >>> local line >>> (( i++ )) >>> echo "text_buffer (block $i):" >>> if [ ! -z "$text_buffer" ]; then >>> while read -r line; do >>> if [ -z "$line" ]; then >>> echo "empty_line" >>> else >>> echo "$line" >>> fi >>> done <<< "$text_buffer" >>> fi >>> echo "test_buffer (block $i):" >>> [ ! -z "$test_buffer" ] && echo "$test_buffer" >>> echo "output_buffer (block $i):" >>> [ ! -z "$output_buffer" ] && echo "$output_buffer" >>> return 0 >>> } >>> doc_test_parse_doc_string "$doc_string" _ "(test)" text_buffer (block 1): Some text (block 1). empty_line empty_line Some more text (block 1). test_buffer (block 1): output_buffer (block 1): text_buffer (block 2): test_buffer (block 2): block 2 block 2.2 output_buffer (block 2): output block 2 text_buffer (block 3): test_buffer (block 3): block 3 output_buffer (block 3): output block 3 text_buffer (block 4): Even more text (block 4). test_buffer (block 4): output_buffer (block 4):Function documentation_serve
Serves a readme via webserver. Uses Flatdoc.
>>> # TODO write test >>> echo hans hans
NOTE: The try block is executed in a subshell, so no outer variables can be assigned.
>>> exceptions.activate >>> false +doc_test_ellipsis Traceback (most recent call first): ...
>>> exceptions_activate >>> exceptions.try { >>> false >>> }; exceptions.catch { >>> echo caught >>> } caught
Exceptions in a subshell:
>>> exceptions_activate >>> ( false ) +doc_test_ellipsis Traceback (most recent call first): ... Traceback (most recent call first): ...
>>> exceptions_activate >>> exceptions.try { >>> (false; echo "this should not be printed") >>> echo "this should not be printed" >>> }; exceptions.catch { >>> echo caught >>> } +doc_test_ellipsis caught
Nested exceptions:
>>> exceptions_foo() { >>> true >>> exceptions.try { >>> false >>> }; exceptions.catch { >>> echo caught inside foo >>> } >>> false # this is cought at top level >>> echo this should never be printed >>> } >>> >>> exceptions.try { >>> exceptions_foo >>> }; exceptions.catch { >>> echo caught >>> } >>> caught inside foo caught
Exceptions are implicitely active inside try blocks:
>>> foo() { >>> echo $1 >>> true >>> exceptions.try { >>> false >>> }; exceptions.catch { >>> echo caught inside foo >>> } >>> false # this is not caught >>> echo this should never be printed >>> } >>> >>> foo "EXCEPTIONS NOT ACTIVE:" >>> exceptions_activate >>> foo "EXCEPTIONS ACTIVE:" +doc_test_ellipsis EXCEPTIONS NOT ACTIVE: caught inside foo this should never be printed EXCEPTIONS ACTIVE: caught inside foo Traceback (most recent call first): ...
Exceptions inside conditionals:
>>> exceptions_activate >>> false && echo "should not be printed" >>> (false) && echo "should not be printed" >>> exceptions.try { >>> ( >>> false >>> echo "should not be printed" >>> ) >>> }; exceptions.catch { >>> echo caught >>> } caught
Print a caught exception traceback.
>>> exceptions.try { >>> false >>> }; exceptions.catch { >>> echo caught >>> echo "$exceptions_last_traceback" >>> } +doc_test_ellipsis caught Traceback (most recent call first): ...
Different syntax variations are possible.
>>> exceptions.try { >>> ! true >>> }; exceptions.catch { >>> echo caught >>> }
>>> exceptions.try >>> false >>> exceptions.catch { >>> echo caught >>> } caught
>>> exceptions.try >>> false >>> exceptions.catch >>> echo caught caught
>>> exceptions.try { >>> false >>> } >>> exceptions.catch { >>> echo caught >>> } caught
>>> exceptions.try { >>> false >>> } >>> exceptions.catch >>> { >>> echo caught >>> } caughtFunction exceptions_deactivate
>>> set -o errtrace >>> trap 'echo $foo' ERR >>> exceptions.activate >>> trap -p ERR | cut --delimiter "'" --fields 2 >>> exceptions.deactivate >>> trap -p ERR | cut --delimiter "'" --fields 2 exceptions_error_handler echo $foo
The available log levels are: error critical warn info debug
The standard loglevel is critical
>>> logging.get_level >>> logging.get_commands_level critical critical
>>> logging.error error-message >>> logging.critical critical-message >>> logging.warn warn-message >>> logging.info info-message >>> logging.debug debug-message +doc_test_contains error-message critical-message
If the output of commands should be printed, the commands_level needs to be greater than or equal to the log_level.
>>> logging.set_level critical >>> logging.set_commands_level debug >>> echo foo
>>> logging.set_level info >>> logging.set_commands_level info >>> echo foo foo
Another logging prefix can be set by overriding "logging_get_prefix".
>>> logging_get_prefix() { >>> local level=$1 >>> echo "[myprefix - ${level}]" >>> } >>> logging.critical foo [myprefix - critical] foo
"logging.plain" can be used to print at any log level and without the prefix.
>>> logging.set_level critical >>> logging.set_commands_level debug >>> logging.plain foo foo
"logging.cat" can be used to print files (e.g "logging.cat < file.txt") or heredocs. Like "logging.plain", it also prints at any log level and without the prefix.
>>> echo foo | logging.cat foo
>>> logging.set_level info >>> logging.set_commands_level debug >>> logging.debug "not shown" >>> echo "not shown" >>> logging.plain "shown" shownFunction logging_set_file_descriptors
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" test_file:
>>> local test_file="$(mktemp)" >>> logging_set_file_descriptors "$test_file" >>> logging_set_file_descriptors "" >>> echo "test_file:" >"$test_file" >>> logging.cat "$test_file" >>> rm "$test_file" test_file:
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "$test_file" --logging=tee >>> logging.plain foo >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" foo test_file: foo
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "$test_file" --logging=off --commands=file >>> logging.plain not shown >>> echo foo >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" test_file: foo
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "$test_file" --logging=off >>> logging.plain not shown >>> echo foo >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" foo test_file:
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "$test_file" --commands=tee >>> logging.plain logging >>> echo echo >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" logging echo test_file: echo
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "$test_file" --commands=file >>> logging.plain logging >>> echo echo >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" logging test_file: echo
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "$test_file" --logging=file --commands=file >>> logging.plain logging >>> echo echo >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" test_file: logging echo
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "$test_file" --logging=file --commands=file >>> logging.plain logging >>> echo echo >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" test_file: logging echo
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "$test_file" --logging=file --commands=tee >>> logging.plain logging >>> echo echo >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" echo test_file: logging echo
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "$test_file" --logging=file --commands=off >>> logging.plain logging >>> echo echo >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" test_file: logging
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging_set_file_descriptors "$test_file" --logging=tee --commands=tee >>> logging.plain logging >>> echo echo >>> logging_set_file_descriptors "" >>> logging.cat "$test_file" >>> rm "$test_file" logging echo test_file: logging echo
Test exit handler
>>> local test_file fifo >>> test_file="$(mktemp)" >>> fifo=$(logging_set_file_descriptors "$test_file" --commands=tee; \ >>> echo $logging_tee_fifo) >>> [ -p "$fifo" ] || echo fifo deleted >>> rm "$test_file" fifo deletedFunction logging_set_level
>>> logging.set_commands_level info >>> logging.set_level info >>> echo $logging_level >>> echo $logging_commands_level 3 3Function logging_set_log_file
>>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging.set_log_file "$test_file" >>> logging.plain logging >>> logging.set_log_file "$test_file" >>> echo echo >>> logging.set_log_file "" >>> logging.cat "$test_file" >>> rm "$test_file" logging echo test_file: logging echo
>>> logging.set_commands_level debug >>> logging.set_level debug >>> local test_file="$(mktemp)" >>> logging.plain "test_file:" >"$test_file" >>> logging.set_log_file "$test_file" >>> logging.plain 1 >>> logging.set_log_file "" >>> logging.set_log_file "$test_file" >>> logging.plain 2 >>> logging.set_log_file "" >>> logging.cat "$test_file" >>> rm "$test_file" 1 2 test_file: 1 2
This module provides variables for printing colorful and unicode glyphs. The Terminal features are detected automatically but can also be enabled/disabled manually (see ui.enable_color and ui.enable_unicode_glyphs).
Function ui_disable_colorDisables color output explicitly.
>>> ui.enable_color >>> ui.disable_color >>> echo -E "$ui_color_red" red "$ui_color_default" redFunction ui_disable_unicode_glyphs
Disables unicode glyphs explicitly.
>>> ui.enable_unicode_glyphs >>> ui.disable_unicode_glyphs >>> echo -E "$ui_powerline_ok" +
Enables color output explicitly.
>>> ui.disable_color >>> ui.enable_color >>> echo -E $ui_color_red red $ui_color_default �[0;31m red �[0mFunction ui_enable_unicode_glyphs
Enables unicode glyphs explicitly.
>>> ui.disable_unicode_glyphs >>> ui.enable_unicode_glyphs >>> echo -E "$ui_powerline_ok" ✔Function utils_dependency_check
This function check if all given dependencies are present.
>>> utils_dependency_check mkdir ls; echo $? 0
>>> utils_dependency_check mkdir __not_existing__ 1>/dev/null; echo $? 2
>>> utils_dependency_check __not_existing__ 1>/dev/null; echo $? 2
>>> utils_dependency_check "ls __not_existing__"; echo $? __not_existing__ 2Function utils_dependency_check_pkgconfig
This function check if all given libraries can be found.
>>> utils_dependency_check_shared_library libc.so; echo $? 0
>>> utils_dependency_check_shared_library libc.so __not_existing__ 1>/dev/null; echo $? 2
>>> utils_dependency_check_shared_library __not_existing__ 1>/dev/null; echo $? 2Function utils_dependency_check_shared_library
This function check if all given shared libraries can be found.
>>> utils_dependency_check_shared_library libc.so; echo $? 0
>>> utils_dependency_check_shared_library libc.so __not_existing__ 1>/dev/null; echo $? 2
>>> utils_dependency_check_shared_library __not_existing__ 1>/dev/null; echo $? 2Function utils_find_block_device
>>> utils_find_block_device "boot_partition" /dev/sdb1
>>> utils_find_block_device "boot_partition" /dev/sda /dev/sda2
>>> utils_find_block_device "discoverable by blkid" /dev/sda2
>>> utils_find_block_device "_partition" /dev/sdb1 /dev/sdb2
>>> utils_find_block_device "not matching anything" || echo not found not found
>>> utils_find_block_device "" || echo not found not found
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4