mirror of
https://github.com/armbian/configng.git
synced 2026-01-06 10:37:41 -08:00
Initial commit
This commit is contained in:
64
README.md
64
README.md
@@ -1,2 +1,62 @@
|
||||
# configng
|
||||
Next generation bash based configuration API
|
||||
# configrd
|
||||
This is a refactoring of [armbian-config](https://github.com/armbian/config) using [Bash Utility](https://labbots.github.io/bash-utility)
|
||||
embedded in this project. This allows for functional programming in Bash and also modernizes
|
||||
the monolithic nature of armbian-config. Error handling and validation are also included.
|
||||
The idea is to provide an API in Bash that can be called from a TUI, GUI or CLI. Please
|
||||
follow the coding standards which follow Bash Utility functions.
|
||||
|
||||
Why Bash? Well, because it's going to be in every distribution. Striped down distributions
|
||||
may not include Python, C/C++, etc. build/runtime environments
|
||||
|
||||
## Quick start
|
||||
* `sudo apt install git`
|
||||
* `cd ~/`
|
||||
* `git clone https://github.com/armbian/configng.git`
|
||||
* `cd ~/configrd/test`
|
||||
* `sudo ./cpu_test.sh`
|
||||
If all goes well you should see all the functions in cpu.sh called and output diaplayed.
|
||||
|
||||
## Coding standards
|
||||
[Shell Style Guide](https://google.github.io/styleguide/shellguide.html) has some good ideas,
|
||||
but fundementally look at the code in Bash Utility:
|
||||
```
|
||||
# @description Strip characters from the beginning of a string.
|
||||
#
|
||||
# @example
|
||||
# echo "$(string::lstrip "Hello World!" "He")"
|
||||
# #Output
|
||||
# llo World!
|
||||
#
|
||||
# @arg $1 string The input string.
|
||||
# @arg $2 string The characters you want to strip.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout Returns the modified string.
|
||||
string::lstrip() {
|
||||
[[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
printf '%s\n' "${1##$2}"
|
||||
}
|
||||
```
|
||||
|
||||
Functions should follow filename::func_name style. Then you can tell just from the name which
|
||||
file the function is located in. Return codes should also follow a similar pattern:
|
||||
* 0 Successful
|
||||
* 1 Not found
|
||||
* 2 Function missing arguments
|
||||
* 3-255 all other errors
|
||||
|
||||
Validate values:
|
||||
```
|
||||
# Validate minimum frequency is <= maximum frequency
|
||||
[ "$min_freq" -gt "$max_freq" ] && printf "%s: Minimum frequency must be <= maximum frequency\n" "${FUNCNAME[0]}" && return 5
|
||||
```
|
||||
|
||||
Return values should use stdout:
|
||||
```
|
||||
# Return value
|
||||
printf '%s\n' "$(cat $file)"
|
||||
```
|
||||
|
||||
Only use sudo when needed and never run as root!
|
||||
|
||||
22
functions/bash-utility-master/.editorconfig
Normal file
22
functions/bash-utility-master/.editorconfig
Normal file
@@ -0,0 +1,22 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
# for shfmt
|
||||
[*.sh]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
shell_variant = bash
|
||||
switch_case_indent = true
|
||||
space_redirects = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
3
functions/bash-utility-master/.gitignore
vendored
Normal file
3
functions/bash-utility-master/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/tmp
|
||||
gh-pages
|
||||
hugo-docs
|
||||
8
functions/bash-utility-master/.remarkrc
Normal file
8
functions/bash-utility-master/.remarkrc
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"plugins": [
|
||||
"remark-preset-lint-markdown-style-guide",
|
||||
["remark-lint-list-item-spacing", false],
|
||||
["remark-lint-maximum-line-length", false],
|
||||
["remark-lint-no-duplicate-headings", false]
|
||||
]
|
||||
}
|
||||
76
functions/bash-utility-master/CODE_OF_CONDUCT.md
Normal file
76
functions/bash-utility-master/CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at <admin@labbots.com>. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
<https://www.contributor-covenant.org/faq>
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
129
functions/bash-utility-master/CONTRIBUTING.md
Normal file
129
functions/bash-utility-master/CONTRIBUTING.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Contributing to Bash-Utility
|
||||
|
||||
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
|
||||
The following is a set of guidelines for contributing to this project on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
|
||||
|
||||
## Table of Contents
|
||||
- [Code Contributions](#code-contributions)
|
||||
- [Code Guidelines](#code-guidelines)
|
||||
- [Styleguide](#styleguide)
|
||||
- [Bashdoc guideline](#bashdoc-guideline)
|
||||
- [Documentation](#documentation)
|
||||
- [Commit Guidelines](#commit-guidelines)
|
||||
- [Pull Request Guidelines](#pull-request-guidelines)
|
||||
- [Contact](#contact)
|
||||
|
||||
## Code Contributions
|
||||
|
||||
Great, the more, the merrier.
|
||||
|
||||
Sane code contributions are always welcome, whether to the code or documentation.
|
||||
|
||||
Before making a pull request, make sure to follow below guidelines:
|
||||
|
||||
### Code Guidelines
|
||||
|
||||
#### Styleguide
|
||||
|
||||
- Variable names must be meaningful and self-documenting.
|
||||
- Long variable names must be structured by underscores to improve legibility.
|
||||
- Global variables and constants must be ALL CAPS with underscores. (eg., INPUT_FILE)
|
||||
- local variables used within functions must be all lower case with underscores ( only if required ). (eg., input_data)
|
||||
- Variable names can be alphanumeric with underscores. No special characters in variable names.
|
||||
- Variables name must not start with number.
|
||||
- Variables within function must be declared. So the scope of variable is restricted to the function.
|
||||
- Avoid accessing global variables within functions.
|
||||
- Function names must be all lower case with underscores to seperate words (snake_case).
|
||||
- Function name must start with section name followed by 2 colons and then the function name (eg., `array::contains()`)
|
||||
- Try using bash builtins and string substitution as much as possible.
|
||||
- Use printf everywhere instead of echo.
|
||||
- Before adding a new logic, be sure to check the existing code.
|
||||
- Make sure to add the function in appropriate section based on its operation.
|
||||
- Use [shfmt](https://github.com/mvdan/sh) to format the script. Use below command:
|
||||
|
||||
```shell
|
||||
shfmt upload.sh
|
||||
```
|
||||
|
||||
The repo already provides the .editorconfig file, which shfmt reads, so no need for extra flags.
|
||||
You can also install shfmt for various editors, refer their repo for information.
|
||||
Note: This is strictly necessary to maintain consistency, do not skip.
|
||||
|
||||
- Script should pass all [shellcheck](https://www.shellcheck.net/) warnings, if not, then disable the warning and give a valid reason.
|
||||
|
||||
#### Bashdoc guideline
|
||||
|
||||
The documentation is generated based on the function documentation within the script file. So ensure to follow the style so the documentation is
|
||||
properly generated by the generator.
|
||||
|
||||
Follow the below bashdoc template to add function introductory comment.
|
||||
|
||||
```bash
|
||||
# @description Multiline description goes here and
|
||||
# there
|
||||
#
|
||||
# @example
|
||||
# sample::function a b c
|
||||
# echo 123
|
||||
#
|
||||
# @arg $1 string Some arg.
|
||||
# @arg $2 any Rest of arguments.
|
||||
#
|
||||
# @noargs
|
||||
#
|
||||
# @exitcode 0 If successfull.
|
||||
# @exitcode >0 On failure
|
||||
# @exitcode 5 On some error.
|
||||
#
|
||||
# @stdout Path to something.
|
||||
#
|
||||
# @see sample::other_function(()
|
||||
sample::function() {
|
||||
}
|
||||
```
|
||||
|
||||
- Each function must have a description detailing what the function does and a sample usage example to show how the function can be used.
|
||||
- specify whether the function accepts args or no args by specifying @arg or @noargs tag in the comment.
|
||||
- Make sure to document the exitcode emitted by the function.
|
||||
- If the function is similar to other function add a reference to function using @see tag.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Refrain from making unnecessary newlines or whitespace.
|
||||
- Use pure markdown as much as possible, html is accepted but shouldn't be a priority.
|
||||
- The markdown must pass RemarkLint checks.
|
||||
- The function documentation and Table of Content is autogenerated using `generate_readme.sh`. So DO NOT edit them manually. Use the following command to update ToC and Bashdoc.
|
||||
|
||||
```bash
|
||||
./bin/generate_readme.sh -f README.md -s src/
|
||||
```
|
||||
|
||||
### Commit Guidelines
|
||||
|
||||
It is recommended to use small commits over one large commit. Small, focused commits make the review process easier and are more likely to be accepted.
|
||||
|
||||
It is also important to summarise the changes made with brief commit messages. If the commit fixes a specific issue, it is also good to note that in the commit message.
|
||||
|
||||
The commit message should start with a single line that briefly describes the changes. That should be followed by a blank line and then a more detailed explanation.
|
||||
|
||||
Before committing check for unnecessary whitespace with `git diff --check`.
|
||||
|
||||
### Pull Request Guidelines
|
||||
|
||||
The following guidelines will increase the likelihood that your pull request will get accepted:
|
||||
|
||||
- Follow the commit and code guidelines.
|
||||
- Keep the patches on topic and focused.
|
||||
- Try to avoid unnecessary formatting and clean-up where reasonable.
|
||||
|
||||
A pull request should contain the following:
|
||||
|
||||
- At least one commit (all of which should follow the Commit Guidelines).
|
||||
- Title that summarises the issue/feature.
|
||||
- Description that briefly summarises the changes.
|
||||
|
||||
After submitting a pull request, you should get a response within 7 days. If you do not, don't hesitate to ping the thread.
|
||||
|
||||
## Contact
|
||||
|
||||
For further inquiries, you can contact the developer by opening an issue on the repository.
|
||||
21
functions/bash-utility-master/LICENSE
Normal file
21
functions/bash-utility-master/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 labbots
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
3026
functions/bash-utility-master/README.md
Normal file
3026
functions/bash-utility-master/README.md
Normal file
File diff suppressed because it is too large
Load Diff
20
functions/bash-utility-master/bash_utility.sh
Executable file
20
functions/bash-utility-master/bash_utility.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
source src/array.sh
|
||||
source src/string.sh
|
||||
source src/variable.sh
|
||||
source src/file.sh
|
||||
source src/misc.sh
|
||||
source src/date.sh
|
||||
source src/interaction.sh
|
||||
source src/check.sh
|
||||
source src/format.sh
|
||||
source src/collection.sh
|
||||
source src/json.sh
|
||||
source src/terminal.sh
|
||||
source src/validation.sh
|
||||
source src/debug.sh
|
||||
source src/os.sh
|
||||
|
||||
|
||||
275
functions/bash-utility-master/bin/bashdoc.awk
Executable file
275
functions/bash-utility-master/bin/bashdoc.awk
Executable file
@@ -0,0 +1,275 @@
|
||||
#!/usr/bin/awk -f
|
||||
|
||||
# Varibles
|
||||
# style = readme or doc
|
||||
# toc = true or false
|
||||
BEGIN {
|
||||
if (! style) {
|
||||
style = "doc"
|
||||
}
|
||||
|
||||
if (! toc) {
|
||||
toc = 0
|
||||
}
|
||||
|
||||
styles["empty", "from"] = ".*"
|
||||
styles["empty", "to"] = ""
|
||||
|
||||
styles["h1", "from"] = ".*"
|
||||
styles["h1", "to"] = "# &"
|
||||
|
||||
styles["h2", "from"] = ".*"
|
||||
styles["h2", "to"] = "## &"
|
||||
|
||||
styles["h3", "from"] = ".*"
|
||||
styles["h3", "to"] = "### &"
|
||||
|
||||
styles["h4", "from"] = ".*"
|
||||
styles["h4", "to"] = "#### &"
|
||||
|
||||
styles["h5", "from"] = ".*"
|
||||
styles["h5", "to"] = "##### &"
|
||||
|
||||
styles["code", "from"] = ".*"
|
||||
styles["code", "to"] = "```&"
|
||||
|
||||
styles["/code", "to"] = "```"
|
||||
|
||||
styles["argN", "from"] = "^(\\$[0-9]) (\\S+)"
|
||||
styles["argN", "to"] = "**\\1** (\\2):"
|
||||
|
||||
styles["arg@", "from"] = "^\\$@ (\\S+)"
|
||||
styles["arg@", "to"] = "**...** (\\1):"
|
||||
|
||||
styles["li", "from"] = ".*"
|
||||
styles["li", "to"] = "- &"
|
||||
|
||||
styles["i", "from"] = ".*"
|
||||
styles["i", "to"] = "*&*"
|
||||
|
||||
styles["anchor", "from"] = ".*"
|
||||
styles["anchor", "to"] = "[&](#&)"
|
||||
|
||||
styles["exitcode", "from"] = "([>!]?[0-9]{1,3}) (.*)"
|
||||
styles["exitcode", "to"] = "**\\1**: \\2"
|
||||
|
||||
styles["h_rule", "to"] = "---"
|
||||
|
||||
styles["comment", "from"] = ".*"
|
||||
styles["comment", "to"] = "<!-- & -->"
|
||||
|
||||
|
||||
output_format["readme", "h1"] = "h2"
|
||||
output_format["readme", "h2"] = "h3"
|
||||
output_format["readme", "h3"] = "h4"
|
||||
output_format["readme", "h4"] = "h5"
|
||||
|
||||
output_format["bashdoc", "h1"] = "h1"
|
||||
output_format["bashdoc", "h2"] = "h2"
|
||||
output_format["bashdoc", "h3"] = "h3"
|
||||
output_format["bashdoc", "h4"] = "h4"
|
||||
|
||||
output_format["webdoc", "h1"] = "empty"
|
||||
output_format["webdoc", "h2"] = "h3"
|
||||
output_format["webdoc", "h3"] = "h4"
|
||||
output_format["webdoc", "h4"] = "h5"
|
||||
|
||||
}
|
||||
|
||||
function render(type, text) {
|
||||
if((style,type) in output_format){
|
||||
type = output_format[style,type]
|
||||
}
|
||||
return gensub( \
|
||||
styles[type, "from"],
|
||||
styles[type, "to"],
|
||||
"g",
|
||||
text \
|
||||
)
|
||||
}
|
||||
|
||||
function render_list(item, anchor) {
|
||||
return "- [" item "](#" anchor ")"
|
||||
}
|
||||
|
||||
function generate_anchor(text) {
|
||||
# https://github.com/jch/html-pipeline/blob/master/lib/html/pipeline/toc_filter.rb#L44-L45
|
||||
text = tolower(text)
|
||||
gsub(/[^[:alnum:]_ -]/, "", text)
|
||||
gsub(/ /, "-", text)
|
||||
return text
|
||||
}
|
||||
|
||||
function reset() {
|
||||
has_example = 0
|
||||
has_args = 0
|
||||
has_exitcode = 0
|
||||
has_stdout = 0
|
||||
|
||||
content_desc = ""
|
||||
content_example = ""
|
||||
content_args = ""
|
||||
content_exitcode = ""
|
||||
content_seealso = ""
|
||||
content_stdout = ""
|
||||
}
|
||||
|
||||
/^[[:space:]]*# @internal/ {
|
||||
is_internal = 1
|
||||
}
|
||||
|
||||
/^[[:space:]]*# @file/ {
|
||||
sub(/^[[:space:]]*# @file /, "")
|
||||
|
||||
filedoc = render("h1", $0) "\n"
|
||||
if(style == "webdoc"){
|
||||
filedoc = filedoc render("comment", "file=" $0) "\n"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/^[[:space:]]*# @brief/ {
|
||||
sub(/^[[:space:]]*# @brief /, "")
|
||||
if(style == "webdoc"){
|
||||
filedoc = filedoc render("comment", "brief=" $0) "\n"
|
||||
}
|
||||
filedoc = filedoc "\n" $0
|
||||
}
|
||||
|
||||
/^[[:space:]]*# @description/ {
|
||||
in_description = 1
|
||||
in_example = 0
|
||||
|
||||
reset()
|
||||
|
||||
docblock = ""
|
||||
}
|
||||
|
||||
in_description {
|
||||
if (/^[^[[:space:]]*#]|^[[:space:]]*# @[^d]|^[[:space:]]*[^#]/) {
|
||||
if (!match(content_desc, /\n$/)) {
|
||||
content_desc = content_desc "\n"
|
||||
}
|
||||
in_description = 0
|
||||
} else {
|
||||
sub(/^[[:space:]]*# @description /, "")
|
||||
sub(/^[[:space:]]*# /, "")
|
||||
sub(/^[[:space:]]*#$/, "")
|
||||
|
||||
content_desc = content_desc "\n" $0
|
||||
}
|
||||
}
|
||||
|
||||
in_example {
|
||||
|
||||
if (! /^[[:space:]]*#[ ]{3}/) {
|
||||
|
||||
in_example = 0
|
||||
|
||||
content_example = content_example "\n" render("/code") "\n"
|
||||
} else {
|
||||
sub(/^[[:space:]]*#[ ]{3}/, "")
|
||||
|
||||
content_example = content_example "\n" $0
|
||||
}
|
||||
}
|
||||
|
||||
/^[[:space:]]*# @example/ {
|
||||
in_example = 1
|
||||
content_example = content_example "\n" render("h3", "Example")
|
||||
content_example = content_example "\n\n" render("code", "bash")
|
||||
}
|
||||
|
||||
/^[[:space:]]*# @arg/ {
|
||||
if (!has_args) {
|
||||
has_args = 1
|
||||
|
||||
content_args = content_args "\n" render("h3", "Arguments") "\n\n"
|
||||
}
|
||||
|
||||
sub(/^[[:space:]]*# @arg /, "")
|
||||
|
||||
$0 = render("argN", $0)
|
||||
$0 = render("arg@", $0)
|
||||
|
||||
content_args = content_args render("li", $0) "\n"
|
||||
}
|
||||
|
||||
/^[[:space:]]*# @noargs/ {
|
||||
content_args = content_args "\n" render("i", "Function has no arguments.") "\n"
|
||||
}
|
||||
|
||||
/^[[:space:]]*# @exitcode/ {
|
||||
if (!has_exitcode) {
|
||||
has_exitcode = 1
|
||||
|
||||
content_exitcode = content_exitcode "\n" render("h3", "Exit codes") "\n\n"
|
||||
}
|
||||
|
||||
sub(/^[[:space:]]*# @exitcode /, "")
|
||||
|
||||
$0 = render("exitcode", $0)
|
||||
|
||||
content_exitcode = content_exitcode render("li", $0) "\n"
|
||||
}
|
||||
|
||||
/^[[:space:]]*# @see/ {
|
||||
sub(/[[:space:]]*# @see /, "")
|
||||
anchor = generate_anchor($0)
|
||||
$0 = render_list($0, anchor)
|
||||
|
||||
content_seealso = content_seealso "\n" render("h3", "See also") "\n\n" $0 "\n"
|
||||
}
|
||||
|
||||
/^[[:space:]]*# @stdout/ {
|
||||
has_stdout = 1
|
||||
|
||||
sub(/^[[:space:]]*# @stdout /, "")
|
||||
|
||||
content_stdout = content_stdout "\n" render("h3", "Output on stdout")
|
||||
content_stdout = content_stdout "\n\n" render("li", $0) "\n"
|
||||
}
|
||||
|
||||
{
|
||||
docblock = content_desc content_args content_exitcode content_stdout content_example content_seealso
|
||||
if(style == "webdoc"){
|
||||
docblock = docblock "\n" render("h_rule") "\n"
|
||||
}
|
||||
}
|
||||
|
||||
/^[ \t]*(function([ \t])+)?([a-zA-Z0-9_:-]+)([ \t]*)(\(([ \t]*)\))?[ \t]*\{/ && docblock != "" && !in_example {
|
||||
if (is_internal) {
|
||||
is_internal = 0
|
||||
} else {
|
||||
func_name = gensub(\
|
||||
/^[ \t]*(function([ \t])+)?([a-zA-Z0-9_:-]+)[ \t]*\(.*/, \
|
||||
"\\3()", \
|
||||
"g" \
|
||||
)
|
||||
doc = doc "\n" render("h2", func_name) "\n" docblock
|
||||
if (toc) {
|
||||
url = generate_anchor(func_name)
|
||||
|
||||
content_idx = content_idx "\n" "- [" func_name "](#" url ")"
|
||||
}
|
||||
}
|
||||
|
||||
docblock = ""
|
||||
reset()
|
||||
}
|
||||
|
||||
END {
|
||||
if (filedoc != "") {
|
||||
print filedoc
|
||||
}
|
||||
|
||||
if (toc) {
|
||||
print ""
|
||||
print render("h2", "Table of Contents")
|
||||
print content_idx
|
||||
print ""
|
||||
print render("h_rule")
|
||||
}
|
||||
|
||||
print doc
|
||||
}
|
||||
400
functions/bash-utility-master/bin/generate_readme.sh
Executable file
400
functions/bash-utility-master/bin/generate_readme.sh
Executable file
@@ -0,0 +1,400 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#https://github.com/bkrem/make-toc.sh/blob/master/make-toc.sh
|
||||
#https://gitlab.com/pedrolab/doctoc.sh/-/blob/master/doctoc.sh
|
||||
_usage() {
|
||||
printf "
|
||||
Script to autogenerate markdown based on bash source code.\n
|
||||
The script generates table of contents and bashdoc and update the given markdown file.\n
|
||||
Usage:\n %s [options.. ]\n
|
||||
Options:\n
|
||||
-f | --file <filename.md> - Relative or absolute path to the README.md file.
|
||||
-s | --sh-dir <folderpath> - path to the bash script source folder to generate shdocs.\n
|
||||
-l | --toc-level <number> - Minimum level of header to print in Table of Contents.\n
|
||||
-d | --toc-depth <number> - Maximum depth of tree to print in Table of Contents.\n
|
||||
-w | --webdoc - Flag to indicate generation of webdoc.\n
|
||||
-p | --dest-dir <folderpath> - Path in which wedoc files must be generated.\n
|
||||
-h | --help - Display usage instructions.\n" "${0##*/}"
|
||||
exit 0
|
||||
}
|
||||
|
||||
_setup_arguments() {
|
||||
|
||||
unset MINLEVEL MAXLEVEL SCRIPT_FILE SOURCE_MARKDOWN SOURCE_SCRIPT_DIR SCRIPT_DIR WEBDOC WEBDOC_DEST_DIR
|
||||
MINLEVEL=1
|
||||
MAXLEVEL=3
|
||||
SCRIPT_FILE="${0##*/}"
|
||||
declare source="${BASH_SOURCE[0]}"
|
||||
while [ -h "$source" ]; do # resolve $source until the file is no longer a symlink
|
||||
SCRIPT_DIR="$(cd -P "$(dirname "$source")" > /dev/null 2>&1 && pwd)"
|
||||
source="$(readlink "$source")"
|
||||
[[ $source != /* ]] && source="$SCRIPT_DIR/$source" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
SCRIPT_DIR="$(cd -P "$(dirname "$source")" > /dev/null 2>&1 && pwd)"
|
||||
SOURCE_MARKDOWN="${SCRIPT_DIR}/../README.md"
|
||||
SOURCE_SCRIPT_DIR="${SCRIPT_DIR}/../src"
|
||||
WEBDOC_DEST_DIR="${SCRIPT_DIR}/../hugo-docs/content/functions"
|
||||
|
||||
SHORTOPTS="whp:f:m:d:s:-:"
|
||||
|
||||
while getopts "${SHORTOPTS}" OPTION; do
|
||||
case "${OPTION}" in
|
||||
-)
|
||||
_check_longoptions() { { [[ -z "$1" ]] && printf '%s: --%s: option requires an argument\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1; } || :; }
|
||||
case "${OPTARG}" in
|
||||
help)
|
||||
_usage
|
||||
;;
|
||||
file)
|
||||
_check_longoptions "${!OPTIND}"
|
||||
SOURCE_MARKDOWN="${!OPTIND}" && OPTIND=$((OPTIND + 1))
|
||||
;;
|
||||
toc-level)
|
||||
_check_longoptions "${!OPTIND}"
|
||||
MINLEVEL="${!OPTIND}" && OPTIND=$((OPTIND + 1))
|
||||
;;
|
||||
toc-depth)
|
||||
_check_longoptions "${!OPTIND}"
|
||||
MAXLEVEL="${!OPTIND}" && OPTIND=$((OPTIND + 1))
|
||||
;;
|
||||
sh-dir)
|
||||
_check_longoptions "${!OPTIND}"
|
||||
SOURCE_SCRIPT_DIR="${!OPTIND}" && OPTIND=$((OPTIND + 1))
|
||||
;;
|
||||
webdoc)
|
||||
WEBDOC=true
|
||||
;;
|
||||
dest-dir)
|
||||
WEBDOC_DEST_DIR="${OPTARG}"
|
||||
;;
|
||||
'')
|
||||
_usage
|
||||
;;
|
||||
*)
|
||||
printf '%s: --%s: Unknown option\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
h)
|
||||
_usage
|
||||
;;
|
||||
f)
|
||||
SOURCE_MARKDOWN="${OPTARG}"
|
||||
;;
|
||||
m)
|
||||
MINLEVEL="${OPTARG}"
|
||||
;;
|
||||
d)
|
||||
MAXLEVEL="${OPTARG}"
|
||||
;;
|
||||
s)
|
||||
SOURCE_SCRIPT_DIR="${OPTARG}"
|
||||
;;
|
||||
w)
|
||||
WEBDOC=true
|
||||
;;
|
||||
p)
|
||||
WEBDOC_DEST_DIR="${OPTARG}"
|
||||
;;
|
||||
:)
|
||||
printf '%s: -%s: option requires an argument\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1
|
||||
;;
|
||||
?)
|
||||
printf '%s: -%s: Unknown option\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift "$((OPTIND - 1))"
|
||||
|
||||
if [[ -w "${SOURCE_MARKDOWN}" ]]; then
|
||||
declare src_file src_extension
|
||||
src_file="${SOURCE_MARKDOWN##*/}"
|
||||
src_extension="${src_file##*.}"
|
||||
if [[ "${src_extension,,}" != "md" ]]; then
|
||||
printf "Provided file %s is not a markdown.\n" "${src_file}" && exit 1
|
||||
fi
|
||||
else
|
||||
printf "Provided file %s does not exist or no enough permission to access it.\n" "${SOURCE_MARKDOWN}" && exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "${SOURCE_SCRIPT_DIR}" ]]; then
|
||||
printf "Provided directory for bash script files %s does not exist.\n" "${SOURCE_SCRIPT_DIR}" && exit 1
|
||||
fi
|
||||
|
||||
declare re='^[0-9]+$'
|
||||
if ! [[ "${MINLEVEL}" =~ $re ]] || ! [[ "${MAXLEVEL}" =~ $re ]]; then
|
||||
echo "error: Not a number" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${MINLEVEL}" -gt "${MAXLEVEL}" ]]; then
|
||||
printf "Minimum level for TOC cannot be greater than the depth of TOC to be printed.\n" && exit 1
|
||||
fi
|
||||
|
||||
[ -d "${WEBDOC_DEST_DIR}" ] || mkdir -p "${WEBDOC_DEST_DIR}"
|
||||
|
||||
}
|
||||
|
||||
_setup_tempfile() {
|
||||
declare temp_file
|
||||
type -p mktemp &> /dev/null && { temp_file="$(mktemp -u)" || temp_file="${PWD}/$((RANDOM * 2)).LOG"; }
|
||||
trap 'rm -f "${temp_file}"' EXIT
|
||||
printf "%s" "${temp_file}"
|
||||
}
|
||||
|
||||
_generate_shdoc() {
|
||||
declare file
|
||||
file="$(realpath "${1}")"
|
||||
if [[ -s "${file}" ]]; then
|
||||
awk -v style="readme" -v toc=0 -f "${SCRIPT_DIR}"/bashdoc.awk < "${file}" >> "$2"
|
||||
#awk -v style="doc" -v toc=1 -f "${SCRIPT_DIR}"/bashdoc.awk < "${file}" >> "../docs/${file##*/}.md"
|
||||
fi
|
||||
}
|
||||
|
||||
_insert_shdoc_to_file() {
|
||||
declare shdoc_tmp_file source_markdown start_shdoc info_shdoc end_shdoc
|
||||
shdoc_tmp_file="$1"
|
||||
source_markdown="$2"
|
||||
|
||||
start_shdoc="<!-- START ${SCRIPT_FILE} generated SHDOC please keep comment here to allow auto update -->"
|
||||
info_shdoc="<!-- DO NOT EDIT THIS SECTION, INSTEAD RE-RUN ${SCRIPT_FILE} TO UPDATE -->"
|
||||
end_shdoc="<!-- END ${SCRIPT_FILE} generated SHDOC please keep comment here to allow auto update -->"
|
||||
|
||||
sed -i "1s/^/${info_shdoc}\n/" "${shdoc_tmp_file}"
|
||||
|
||||
if grep --color=always -Pzl "(?s)${start_shdoc}.*\n.*${end_shdoc}" "${source_markdown}" &> /dev/null; then
|
||||
# src https://stackoverflow.com/questions/2699666/replace-delimited-block-of-text-in-file-with-the-contents-of-another-file
|
||||
|
||||
sed -i -ne "/${start_shdoc}/ {p; r ${shdoc_tmp_file}" -e ":a; n; /${end_shdoc}/ {p; b}; ba}; p" "${source_markdown}"
|
||||
echo -e "Updated bashdoc content to ${source_markdown} successfully\n"
|
||||
|
||||
else
|
||||
{
|
||||
printf "%s\n" "${start_shdoc}"
|
||||
cat "${shdoc_tmp_file}"
|
||||
printf "%s\n" "${end_shdoc}"
|
||||
} >> "${source_markdown}"
|
||||
echo -e "Created bashdoc content to ${source_markdown} successfully\n"
|
||||
fi
|
||||
}
|
||||
|
||||
_process_sh_files() {
|
||||
declare shdoc_tmp_file source_script_dir source_markdown
|
||||
source_markdown="${1}"
|
||||
source_script_dir="${2}"
|
||||
shdoc_tmp_file=$(_setup_tempfile)
|
||||
find "${source_script_dir}" -name '*.sh' -print0 | sort -z |
|
||||
while IFS= read -r -d '' line; do
|
||||
_generate_shdoc "${line}" "${shdoc_tmp_file}"
|
||||
done
|
||||
_insert_shdoc_to_file "${shdoc_tmp_file}" "${source_markdown}"
|
||||
rm "${shdoc_tmp_file}"
|
||||
|
||||
}
|
||||
|
||||
_generate_toc() {
|
||||
|
||||
declare line level title anchor output counter temp_output invalid_chars
|
||||
|
||||
invalid_chars="'[]/?!:\`.,()*\";{}+=<>~$|#@&–—"
|
||||
while IFS='' read -r line || [[ -n "${line}" ]]; do
|
||||
level="$(echo "${line}" | sed -E 's/(#+).*/\1/; s/#/ /g; s/^ //')"
|
||||
title="$(echo "${line}" | sed -E 's/^#+ //')"
|
||||
[[ "${title}" = "Table of Contents" ]] && continue
|
||||
|
||||
# tr does not do OK the lowercase for non ascii chars, add sed to pipeline -> src https://stackoverflow.com/questions/13381746/tr-upper-lower-with-cyrillic-text
|
||||
anchor="$(echo "${title}" | tr '[:upper:] ' '[:lower:]-' | sed 's/[[:upper:]]*/\L&/' | tr -d "${invalid_chars}")"
|
||||
|
||||
# check new line introduced is not duplicated, if is duplicated, introduce a number at the end
|
||||
temp_output=$output"$level- [$title](#$anchor)\n"
|
||||
counter=1
|
||||
while true; do
|
||||
nlines="$(echo -e "${temp_output}" | wc -l)"
|
||||
duplines="$(echo -e "${temp_output}" | sort | uniq | wc -l)"
|
||||
if [ "${nlines}" = "${duplines}" ]; then
|
||||
break
|
||||
fi
|
||||
temp_output=$output"$level- [$title](#$anchor-$counter)\n"
|
||||
counter=$((counter + 1))
|
||||
done
|
||||
|
||||
output="$temp_output"
|
||||
|
||||
# grep: filter header candidates to be included in toc
|
||||
# sed: remove the ignored headers (case: minlevel greater than one) to avoid unnecessary spacing later in level variable assignment
|
||||
done <<< "$(grep -E "^#{${MINLEVEL},${MAXLEVEL}} " "${1}" | tr -d '\r' | sed "s/^#\{$((MINLEVEL - 1))\}//g")"
|
||||
|
||||
# when in toc we have two `--` quit one
|
||||
echo "$output"
|
||||
|
||||
}
|
||||
|
||||
_insert_toc_to_file() {
|
||||
|
||||
declare source_markdown toc_text start_toc info_toc end_toc toc_block utext_ampersand utext_slash
|
||||
source_markdown="${1}"
|
||||
toc_text="${2}"
|
||||
start_toc="<!-- START ${SCRIPT_FILE} generated TOC please keep comment here to allow auto update -->"
|
||||
info_toc="<!-- DO NOT EDIT THIS SECTION, INSTEAD RE-RUN ${SCRIPT_FILE} TO UPDATE -->"
|
||||
end_toc="<!-- END ${SCRIPT_FILE} generated TOC please keep comment here to allow auto update -->"
|
||||
|
||||
toc_block="$start_toc\n$info_toc\n## Table of Contents\n\n$toc_text\n$end_toc"
|
||||
# temporary replace of '/' (confused with separator of substitutions) and '&' (confused with match regex symbol) to run the special sed command
|
||||
utext_ampersand="id8234923000230gzz"
|
||||
utext_slash="id9992384923423gzz"
|
||||
toc_block="${toc_block//\&/${utext_ampersand}}"
|
||||
toc_block="${toc_block//\//${utext_slash}}"
|
||||
|
||||
# search multiline toc block -> https://stackoverflow.com/questions/2686147/how-to-find-patterns-across-multiple-lines-using-grep/2686705
|
||||
# grep color for debugging -> https://superuser.com/questions/914856/grep-display-all-output-but-highlight-search-matches
|
||||
if grep --color=always -Pzl "(?s)${start_toc}.*\n.*${end_toc}" "${source_markdown}" &> /dev/null; then
|
||||
# src https://askubuntu.com/questions/533221/how-do-i-replace-multiple-lines-with-single-word-in-fileinplace-replace
|
||||
sed -i ":a;N;\$!ba;s/$start_toc.*$end_toc/$toc_block/g" "${source_markdown}"
|
||||
echo -e "Updated TOC content in ${source_markdown} succesfully\n"
|
||||
|
||||
else
|
||||
sed -i 1i"$toc_block" "${source_markdown}"
|
||||
echo -e "Created TOC in ${source_markdown} succesfully\n"
|
||||
|
||||
fi
|
||||
|
||||
# undo symbol replacements
|
||||
sed -i "s,${utext_ampersand},\&,g" "${source_markdown}"
|
||||
sed -i "s,${utext_slash},\/,g" "${source_markdown}"
|
||||
|
||||
}
|
||||
|
||||
_process_toc() {
|
||||
declare toc_temp_file source_markdown level toc_text
|
||||
source_markdown="${1}"
|
||||
|
||||
toc_temp_file=$(_setup_tempfile)
|
||||
|
||||
sed '/```/,/```/d' "${source_markdown}" > "${toc_temp_file}"
|
||||
|
||||
level=$MINLEVEL
|
||||
while [[ $(grep -Ec "^#{$level} " "${toc_temp_file}") -le 1 ]]; do
|
||||
level=$((level + 1))
|
||||
done
|
||||
|
||||
MINLEVEL=${level}
|
||||
toc_text=$(_generate_toc "${toc_temp_file}")
|
||||
rm "${toc_temp_file}"
|
||||
|
||||
_insert_toc_to_file "${source_markdown}" "${toc_text}"
|
||||
}
|
||||
|
||||
_generate_webdoc() {
|
||||
declare dest_dir filename file_basename dest_file_path shdoc_tmp_file is_new_file
|
||||
declare title description start_shdoc end_shdoc file_modified_date file_modified_date_epoc
|
||||
declare webdoc_lastmod_date webdoc_lastmod_epoc
|
||||
file="$(realpath "${1}")"
|
||||
dest_dir="${2}"
|
||||
|
||||
filename="${file##*/}"
|
||||
file_basename="${filename%.*}"
|
||||
dest_file_path="${dest_dir}/${file_basename}.md"
|
||||
file_modified_date="$(date -r "${file}" +"%FT%T%:z")"
|
||||
file_modified_date_epoc="$(date -r "${file}" +"%s")"
|
||||
|
||||
start_shdoc="<!-- START ${SCRIPT_FILE} generated SHDOC please keep comment here to allow auto update -->"
|
||||
end_shdoc="<!-- END ${SCRIPT_FILE} generated SHDOC please keep comment here to allow auto update -->"
|
||||
if [[ ! -f "${dest_file_path}" ]]; then
|
||||
|
||||
cat << EOF > "${dest_file_path}"
|
||||
---
|
||||
title : <!-- file -->
|
||||
description : <!-- brief -->
|
||||
date : ${file_modified_date}
|
||||
lastmod : ${file_modified_date}
|
||||
---
|
||||
${start_shdoc}
|
||||
${end_shdoc}
|
||||
EOF
|
||||
is_new_file=true
|
||||
else
|
||||
is_new_file=false
|
||||
webdoc_lastmod_date="$(sed -ne 's/-->//; s/^.*lastmod : //p' "${dest_file_path}")"
|
||||
webdoc_lastmod_epoc="$(date -d "${webdoc_lastmod_date}" +"%s")"
|
||||
fi
|
||||
|
||||
if [[ "${is_new_file}" = true || "${file_modified_date_epoc}" -gt "${webdoc_lastmod_epoc}" ]]; then
|
||||
|
||||
shdoc_tmp_file=$(_setup_tempfile)
|
||||
if [[ -s "${file}" ]]; then
|
||||
awk -v style="webdoc" -v toc=1 -f "${SCRIPT_DIR}"/bashdoc.awk < "${file}" >> "${shdoc_tmp_file}"
|
||||
fi
|
||||
|
||||
if grep --color=always -Pzl "(?s)${start_shdoc}.*\n.*${end_shdoc}" "${dest_file_path}" &> /dev/null; then
|
||||
sed -i -ne "/${start_shdoc}/ {p; r ${shdoc_tmp_file}" -e ":a; n; /${end_shdoc}/ {p; b}; ba}; p" "${dest_file_path}"
|
||||
fi
|
||||
|
||||
# Extract title and description from webdoc
|
||||
title="$(sed -ne 's/-->//; s/^.*<!-- file=//p' "${dest_file_path}")"
|
||||
description="$(sed -ne 's/-->//; s/^.*<!-- brief=//p' "${dest_file_path}")"
|
||||
sed -i '/^.*<!-- file=/d' "${dest_file_path}"
|
||||
sed -i '/^.*<!-- brief=/d' "${dest_file_path}"
|
||||
|
||||
# Replace Frontmatter content with values from the document
|
||||
if [[ "${is_new_file}" = true ]]; then
|
||||
|
||||
sed -i -e "s/<!-- file -->/${title}/g" "${dest_file_path}"
|
||||
sed -i -e "s/<!-- brief -->/${description}/g" "${dest_file_path}"
|
||||
else
|
||||
sed -i -e "s/title : .*/title : ${title}/g" "${dest_file_path}"
|
||||
sed -i -e "s/description : .*/description : ${description}/g" "${dest_file_path}"
|
||||
|
||||
fi
|
||||
|
||||
# Update the last modified timestamp in front matter
|
||||
sed -i -e "s/lastmod : .*/lastmod : ${file_modified_date}/g" "${dest_file_path}"
|
||||
|
||||
echo -e "Updated bashdoc content to ${dest_file_path} successfully."
|
||||
rm "${shdoc_tmp_file}"
|
||||
|
||||
fi
|
||||
}
|
||||
_process_webdoc_files() {
|
||||
declare source_script_dir dest_dir
|
||||
|
||||
source_script_dir="${1}"
|
||||
dest_dir="${2}"
|
||||
|
||||
find "${source_script_dir}" -name '*.sh' -print0 | sort -z |
|
||||
while IFS= read -r -d '' line; do
|
||||
_generate_webdoc "${line}" "${dest_dir}"
|
||||
done
|
||||
}
|
||||
|
||||
_count_library_functions() {
|
||||
declare source_script_dir
|
||||
source_script_dir="${1}"
|
||||
|
||||
find "${source_script_dir}" -name '*.sh' -print0 | sort -z |
|
||||
{
|
||||
declare -i function_count=0 count=0
|
||||
while IFS= read -r -d '' line; do
|
||||
count=0
|
||||
count=$(grep -c '^[[:alpha:]]*::[[:alnum:]_]*()' "${line}")
|
||||
function_count=$((function_count + count))
|
||||
done
|
||||
printf "Total library functions: %s \n" "${function_count}"
|
||||
|
||||
}
|
||||
}
|
||||
main() {
|
||||
# export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||
# set -x
|
||||
trap 'exit "$?"' INT TERM && trap 'exit "$?"' EXIT
|
||||
set -o errexit -o noclobber -o pipefail
|
||||
|
||||
_setup_arguments "${@}"
|
||||
_process_sh_files "${SOURCE_MARKDOWN}" "${SOURCE_SCRIPT_DIR}"
|
||||
_process_toc "${SOURCE_MARKDOWN}"
|
||||
|
||||
if [[ -n ${WEBDOC} ]]; then
|
||||
_process_webdoc_files "${SOURCE_SCRIPT_DIR}" "${WEBDOC_DEST_DIR}"
|
||||
fi
|
||||
_count_library_functions "${SOURCE_SCRIPT_DIR}"
|
||||
}
|
||||
|
||||
main "${@}"
|
||||
BIN
functions/bash-utility-master/image/bash-utility.png
Normal file
BIN
functions/bash-utility-master/image/bash-utility.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
functions/bash-utility-master/image/logo.png
Normal file
BIN
functions/bash-utility-master/image/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
284
functions/bash-utility-master/src/array.sh
Executable file
284
functions/bash-utility-master/src/array.sh
Executable file
@@ -0,0 +1,284 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# @file Array
|
||||
# @brief Functions for array operations and manipulations.
|
||||
|
||||
# @description Check if item exists in the given array.
|
||||
#
|
||||
# @example
|
||||
# array=("a" "b" "c")
|
||||
# array::contains "c" ${array[@]}
|
||||
# #Output
|
||||
# 0
|
||||
#
|
||||
# @arg $1 mixed Item to search (needle).
|
||||
# @arg $2 array array to be searched (haystack).
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 1 If no match found in the array.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
array::contains() {
|
||||
[[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare query="${1:-}"
|
||||
shift
|
||||
|
||||
for element in "${@}"; do
|
||||
[[ "${element}" == "${query}" ]] && return 0
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# @description Remove duplicate items from the array.
|
||||
#
|
||||
# @example
|
||||
# array=("a" "b" "a" "c")
|
||||
# printf "%s" "$(array::dedupe ${array[@]})"
|
||||
# #Output
|
||||
# a
|
||||
# b
|
||||
# c
|
||||
#
|
||||
# @arg $1 array Array to be deduped.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout Deduplicated array.
|
||||
array::dedupe() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare -A arr_tmp
|
||||
declare -a arr_unique
|
||||
for i in "$@"; do
|
||||
{ [[ -z ${i} || ${arr_tmp[${i}]} ]]; } && continue
|
||||
arr_unique+=("${i}") && arr_tmp[${i}]=x
|
||||
done
|
||||
printf '%s\n' "${arr_unique[@]}"
|
||||
}
|
||||
|
||||
# @description Check if a given array is empty.
|
||||
#
|
||||
# @example
|
||||
# array=("a" "b" "c" "d")
|
||||
# array::is_empty "${array[@]}"
|
||||
#
|
||||
# @arg $1 array Array to be checked.
|
||||
#
|
||||
# @exitcode 0 If the given array is empty.
|
||||
# @exitcode 2 If the given array is not empty.
|
||||
array::is_empty() {
|
||||
declare -a array
|
||||
local array=("$@")
|
||||
if [ ${#array[@]} -eq 0 ]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
# @description Join array elements with a string.
|
||||
#
|
||||
# @example
|
||||
# array=("a" "b" "c" "d")
|
||||
# printf "%s" "$(array::join "," "${array[@]}")"
|
||||
# #Output
|
||||
# a,b,c,d
|
||||
# printf "%s" "$(array::join "" "${array[@]}")"
|
||||
# #Output
|
||||
# abcd
|
||||
#
|
||||
# @arg $1 string String to join the array elements (glue).
|
||||
# @arg $2 array array to be joined with glue string.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout String containing a string representation of all the array elements in the same order,with the glue string between each element.
|
||||
array::join() {
|
||||
[[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare delimiter="${1}"
|
||||
shift
|
||||
printf "%s" "${1}"
|
||||
shift
|
||||
printf "%s" "${@/#/${delimiter}}"
|
||||
}
|
||||
|
||||
# @description Return an array with elements in reverse order.
|
||||
#
|
||||
# @example
|
||||
# array=(1 2 3 4 5)
|
||||
# printf "%s" "$(array::reverse "${array[@]}")"
|
||||
# #Output
|
||||
# 5 4 3 2 1
|
||||
#
|
||||
# @arg $1 array The input array.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout The reversed array.
|
||||
array::reverse() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare min=0
|
||||
declare -a array
|
||||
array=("$@")
|
||||
declare max=$((${#array[@]} - 1))
|
||||
|
||||
while [[ $min -lt $max ]]; do
|
||||
# Swap current first and last elements
|
||||
x="${array[$min]}"
|
||||
array[$min]="${array[$max]}"
|
||||
array[$max]="$x"
|
||||
|
||||
# Move closer
|
||||
((min++, max--))
|
||||
done
|
||||
printf '%s\n' "${array[@]}"
|
||||
}
|
||||
|
||||
# @description Returns a random item from the array.
|
||||
#
|
||||
# @example
|
||||
# array=("a" "b" "c" "d")
|
||||
# printf "%s\n" "$(array::random_element "${array[@]}")"
|
||||
# #Output
|
||||
# c
|
||||
#
|
||||
# @arg $1 array The input array.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout Random item out of the array.
|
||||
array::random_element() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare -a array
|
||||
local array=("$@")
|
||||
printf '%s\n' "${array[RANDOM % $#]}"
|
||||
}
|
||||
|
||||
# @description Sort an array from lowest to highest.
|
||||
#
|
||||
# @example
|
||||
# sarr=("a c" "a" "d" 2 1 "4 5")
|
||||
# array::array_sort "${sarr[@]}"
|
||||
# #Output
|
||||
# 1
|
||||
# 2
|
||||
# 4 5
|
||||
# a
|
||||
# a c
|
||||
# d
|
||||
#
|
||||
# @arg $1 array The input array.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout sorted array.
|
||||
array::sort() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare -a array=("$@")
|
||||
declare -a sorted
|
||||
declare noglobtate
|
||||
noglobtate="$(shopt -po noglob)"
|
||||
set -o noglob
|
||||
declare IFS=$'\n'
|
||||
sorted=($(sort <<< "${array[*]}"))
|
||||
unset IFS
|
||||
eval "${noglobtate}"
|
||||
printf "%s\n" "${sorted[@]}"
|
||||
}
|
||||
|
||||
# @description Sort an array in reverse order (highest to lowest).
|
||||
#
|
||||
# @example
|
||||
# sarr=("a c" "a" "d" 2 1 "4 5")
|
||||
# array::array_sort "${sarr[@]}"
|
||||
# #Output
|
||||
# d
|
||||
# a c
|
||||
# a
|
||||
# 4 5
|
||||
# 2
|
||||
# 1
|
||||
#
|
||||
# @arg $1 array The input array.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout reverse sorted array.
|
||||
array::rsort() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare -a array=("$@")
|
||||
declare -a sorted
|
||||
declare noglobtate
|
||||
noglobtate="$(shopt -po noglob)"
|
||||
set -o noglob
|
||||
declare IFS=$'\n'
|
||||
sorted=($(sort -r<<< "${array[*]}"))
|
||||
unset IFS
|
||||
eval "${noglobtate}"
|
||||
printf "%s\n" "${sorted[@]}"
|
||||
}
|
||||
|
||||
# @description Bubble sort an integer array from lowest to highest.
|
||||
# This sort does not work on string array.
|
||||
# @example
|
||||
# iarr=(4 5 1 3)
|
||||
# array::bsort "${iarr[@]}"
|
||||
# #Output
|
||||
# 1
|
||||
# 3
|
||||
# 4
|
||||
# 5
|
||||
#
|
||||
# @arg $1 array The input array.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout bubble sorted array.
|
||||
array::bsort() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare tmp
|
||||
declare arr=("$@")
|
||||
for ((i = 0; i <= $((${#arr[@]} - 2)); ++i)); do
|
||||
for ((j = ((i + 1)); j <= ((${#arr[@]} - 1)); ++j)); do
|
||||
if [[ ${arr[i]} -gt ${arr[j]} ]]; then
|
||||
# echo $i $j ${arr[i]} ${arr[j]}
|
||||
tmp=${arr[i]}
|
||||
arr[i]=${arr[j]}
|
||||
arr[j]=$tmp
|
||||
fi
|
||||
done
|
||||
done
|
||||
printf "%s\n" "${arr[@]}"
|
||||
}
|
||||
|
||||
# @description Merge two arrays.
|
||||
# Pass the variable name of the array instead of value of the variable.
|
||||
# @example
|
||||
# a=("a" "c")
|
||||
# b=("d" "c")
|
||||
# array::merge "a[@]" "b[@]"
|
||||
# #Output
|
||||
# a
|
||||
# c
|
||||
# d
|
||||
# c
|
||||
#
|
||||
# @arg $1 string variable name of first array.
|
||||
# @arg $2 string variable name of second array.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout Merged array.
|
||||
array::merge() {
|
||||
[[ $# -ne 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare -a arr1=("${!1}")
|
||||
declare -a arr2=("${!2}")
|
||||
declare out=("${arr1[@]}" "${arr2[@]}")
|
||||
printf "%s\n" "${out[@]}"
|
||||
}
|
||||
34
functions/bash-utility-master/src/check.sh
Executable file
34
functions/bash-utility-master/src/check.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# @file Check
|
||||
# @brief Helper functions.
|
||||
|
||||
# @description Check if the command exists in the system.
|
||||
#
|
||||
# @example
|
||||
# check::command_exists "tput"
|
||||
#
|
||||
# @arg $1 string Command name to be searched.
|
||||
#
|
||||
# @exitcode 0 If the command exists.
|
||||
# @exitcode 1 If the command does not exist.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
check::command_exists() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
hash "${1}" 2> /dev/null
|
||||
}
|
||||
|
||||
# @description Check if the script is executed with sudo privilege.
|
||||
#
|
||||
# @example
|
||||
# check::is_sudo
|
||||
#
|
||||
# @noargs
|
||||
#
|
||||
# @exitcode 0 If the script is executed with root privilege.
|
||||
# @exitcode 1 If the script is not executed with root privilege
|
||||
check::is_sudo() {
|
||||
if [[ $(id -u) -ne 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
287
functions/bash-utility-master/src/collection.sh
Executable file
287
functions/bash-utility-master/src/collection.sh
Executable file
@@ -0,0 +1,287 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# @file Collection
|
||||
# @brief (Experimental) Functions to iterates over a list of elements, yielding each in turn to an iteratee function.
|
||||
|
||||
# @description Iterates over elements of collection and invokes iteratee for each element.
|
||||
# Input to the function can be a pipe output, here-string or file.
|
||||
# @example
|
||||
# test_func(){
|
||||
# printf "print value: %s\n" "$1"
|
||||
# return 0
|
||||
# }
|
||||
# arr1=("a b" "c d" "a" "d")
|
||||
# printf "%s\n" "${arr1[@]}" | collection::each "test_func"
|
||||
# collection::each "test_func" < <(printf "%s\n" "${arr1[@]}") #alternative approach
|
||||
# #output
|
||||
# print value: a b
|
||||
# print value: c d
|
||||
# print value: a
|
||||
# print value: d
|
||||
#
|
||||
# @example
|
||||
# # If other function from this library is already used to process the array.
|
||||
# # Then following method could be used to pass the array to the function.
|
||||
# out=("$(array::dedupe "${arr1[@]}")")
|
||||
# collection::each "test_func" <<< "${out[@]}"
|
||||
#
|
||||
# @arg $1 string Iteratee function.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
# @exitcode other exitcode returned by iteratee.
|
||||
#
|
||||
# @stdout Output of iteratee function.
|
||||
collection::each() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare func="${1}"
|
||||
declare IFS=$'\n'
|
||||
while read -r it; do
|
||||
if [[ "${func}" == *"$"* ]]; then
|
||||
eval "${func}"
|
||||
else
|
||||
eval "${func}" "'${it}'"
|
||||
fi
|
||||
declare -i ret="$?"
|
||||
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
return $ret
|
||||
fi
|
||||
|
||||
done
|
||||
}
|
||||
|
||||
# @description Checks if iteratee function returns truthy for all elements of collection. Iteration is stopped once predicate returns false.
|
||||
# Input to the function can be a pipe output, here-string or file.
|
||||
# @example
|
||||
# arri=("1" "2" "3" "4")
|
||||
# printf "%s\n" "${arri[@]}" | collection::every "variable::is_numeric"
|
||||
#
|
||||
# @arg $1 string Iteratee function.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 1 If iteratee function fails.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
collection::every() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare func="${1}"
|
||||
declare IFS=$'\n'
|
||||
while read -r it; do
|
||||
if [[ "${func}" == *"$"* ]]; then
|
||||
eval "${func}"
|
||||
else
|
||||
eval "${func}" "'${it}'"
|
||||
fi
|
||||
declare -i ret="$?"
|
||||
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
done
|
||||
}
|
||||
|
||||
# @description Iterates over elements of array, returning all elements where iteratee returns true.
|
||||
# Input to the function can be a pipe output, here-string or file.
|
||||
# @example
|
||||
# arri=("1" "2" "3" "a")
|
||||
# printf "%s\n" "${arri[@]}" | collection::filter "variable::is_numeric"
|
||||
# #output
|
||||
# 1
|
||||
# 2
|
||||
# 3
|
||||
#
|
||||
# @arg $1 string Iteratee function.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout array values matching the iteratee function.
|
||||
collection::filter() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare func="${1}"
|
||||
declare IFS=$'\n'
|
||||
while read -r it; do
|
||||
if [[ "${func}" == *"$"* ]]; then
|
||||
eval "${func}"
|
||||
else
|
||||
eval "${func}" "'${it}'"
|
||||
fi
|
||||
declare -i ret="$?"
|
||||
if [[ $ret = 0 ]]; then
|
||||
printf "%s\n" "${it}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# @description Iterates over elements of collection, returning the first element where iteratee returns true.
|
||||
# Input to the function can be a pipe output, here-string or file.
|
||||
# @example
|
||||
# arr=("1" "2" "3" "a")
|
||||
# check_a(){
|
||||
# [[ "$1" = "a" ]]
|
||||
# }
|
||||
# printf "%s\n" "${arr[@]}" | collection::find "check_a"
|
||||
# #Output
|
||||
# a
|
||||
#
|
||||
# @arg $1 string Iteratee function.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 1 If no match found.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout first array value matching the iteratee function.
|
||||
collection::find() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare func="${1}"
|
||||
declare IFS=$'\n'
|
||||
while read -r it; do
|
||||
|
||||
if [[ "${func}" == *"$"* ]]; then
|
||||
eval "${func}"
|
||||
else
|
||||
eval "${func}" "'${it}'"
|
||||
fi
|
||||
declare -i ret="$?"
|
||||
if [[ $ret = 0 ]]; then
|
||||
printf "%s" "${it}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# @description Invokes the iteratee with each element passed as argument to the iteratee.
|
||||
# Input to the function can be a pipe output, here-string or file.
|
||||
# @example
|
||||
# opt=("-a" "-l")
|
||||
# printf "%s\n" "${opt[@]}" | collection::invoke "ls"
|
||||
#
|
||||
# @arg $1 string Iteratee function.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
# @exitcode other exitcode returned by iteratee.
|
||||
#
|
||||
# @stdout Output from the iteratee function.
|
||||
collection::invoke() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare -a args=()
|
||||
declare func="${1}"
|
||||
while read -r it; do
|
||||
args=("${args[@]}" "$it")
|
||||
done
|
||||
|
||||
eval "${func}" "${args[@]}"
|
||||
}
|
||||
|
||||
# @description Creates an array of values by running each element in array through iteratee.
|
||||
# Input to the function can be a pipe output, here-string or file.
|
||||
# @example
|
||||
# arri=("1" "2" "3")
|
||||
# add_one(){
|
||||
# i=${1}
|
||||
# i=$(( i + 1 ))
|
||||
# printf "%s\n" "$i"
|
||||
# }
|
||||
# printf "%s\n" "${arri[@]}" | collection::map "add_one"
|
||||
#
|
||||
# @arg $1 string Iteratee function.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
# @exitcode other exitcode returned by iteratee.
|
||||
#
|
||||
# @stdout Output result of iteratee on value.
|
||||
collection::map() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare func="${1}"
|
||||
declare IFS=$'\n'
|
||||
declare out
|
||||
|
||||
while read -r it; do
|
||||
|
||||
if [[ "${func}" == *"$"* ]]; then
|
||||
out="$("${func}")"
|
||||
else
|
||||
out="$("${func}" "$it")"
|
||||
fi
|
||||
|
||||
declare -i ret=$?
|
||||
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
return $ret
|
||||
fi
|
||||
|
||||
printf "%s\n" "${out}"
|
||||
done
|
||||
}
|
||||
|
||||
# @description The opposite of filter function; this method returns the elements of collection that iteratee does not return true.
|
||||
# Input to the function can be a pipe output, here-string or file.
|
||||
# @example
|
||||
# arri=("1" "2" "3" "a")
|
||||
# printf "%s\n" "${arri[@]}" | collection::reject "variable::is_numeric"
|
||||
# #Ouput
|
||||
# a
|
||||
#
|
||||
# @arg $1 string Iteratee function.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout array values not matching the iteratee function.
|
||||
# @see collection::filter
|
||||
collection::reject() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare func="${1}"
|
||||
declare IFS=$'\n'
|
||||
while read -r it; do
|
||||
|
||||
if [[ "${func}" == *"$"* ]]; then
|
||||
eval "${func}"
|
||||
else
|
||||
eval "${func}" "'$it'"
|
||||
fi
|
||||
declare -i ret=$?
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
echo "$it"
|
||||
fi
|
||||
|
||||
done
|
||||
}
|
||||
|
||||
# @description Checks if iteratee returns true for any element of the array.
|
||||
# Input to the function can be a pipe output, here-string or file.
|
||||
# @example
|
||||
# arr=("a" "b" "3" "a")
|
||||
# printf "%s\n" "${arr[@]}" | collection::reject "variable::is_numeric"
|
||||
#
|
||||
# @arg $1 string Iteratee function.
|
||||
#
|
||||
# @exitcode 0 If match successful.
|
||||
# @exitcode 1 If no match found.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
collection::some() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare func="${1}"
|
||||
declare IFS=$'\n'
|
||||
while read -r it; do
|
||||
|
||||
if [[ "${func}" == *"$"* ]]; then
|
||||
eval "${func}"
|
||||
else
|
||||
eval "${func}" "'$it'"
|
||||
fi
|
||||
|
||||
declare -i ret=$?
|
||||
|
||||
if [[ $ret -eq 0 ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
744
functions/bash-utility-master/src/date.sh
Executable file
744
functions/bash-utility-master/src/date.sh
Executable file
File diff suppressed because it is too large
Load Diff
49
functions/bash-utility-master/src/debug.sh
Executable file
49
functions/bash-utility-master/src/debug.sh
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# @file Debug
|
||||
# @brief Functions to facilitate debugging scripts.
|
||||
|
||||
# @description Prints the content of array as key value pair for easier debugging.
|
||||
# Pass the variable name of the array instead of value of the variable.
|
||||
# @example
|
||||
# array=(foo bar baz)
|
||||
# printf "Array\n"
|
||||
# printarr "array"
|
||||
# declare -A assoc_array
|
||||
# assoc_array=([foo]=bar [baz]=foobar)
|
||||
# printf "Assoc Array\n"
|
||||
# printarr "assoc_array"
|
||||
# #Output
|
||||
# Array
|
||||
# 0 = foo
|
||||
# 1 = bar
|
||||
# 2 = baz
|
||||
# Assoc Array
|
||||
# baz = foobar
|
||||
# foo = bar
|
||||
#
|
||||
# @arg $1 string variable name of the array.
|
||||
#
|
||||
# @stdout Formatted key value of array.
|
||||
debug::print_array() {
|
||||
declare -n __arr="$1"
|
||||
for k in "${!__arr[@]}"; do printf "%s = %s\n" "$k" "${__arr[$k]}"; done
|
||||
}
|
||||
|
||||
# @description Function to print ansi escape sequence as is.
|
||||
# This function helps debug ansi escape sequence in text by displaying the escape codes.
|
||||
#
|
||||
# @example
|
||||
# txt="$(tput bold)$(tput setaf 9)This is bold red text$(tput sgr0).$(tput setaf 10)This is green text$(tput sgr0)"
|
||||
# debug::print_ansi "$txt"
|
||||
# #Output
|
||||
# \e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text\e(B\e[m
|
||||
#
|
||||
# @arg $1 string input with ansi escape sequence.
|
||||
#
|
||||
# @stdout Ansi escape sequence printed in output as is.
|
||||
debug::print_ansi() {
|
||||
#echo $(tr -dc '[:print:]'<<<$1)
|
||||
printf "%s\n" "${1//$'\e'/\\e}"
|
||||
|
||||
}
|
||||
222
functions/bash-utility-master/src/file.sh
Executable file
222
functions/bash-utility-master/src/file.sh
Executable file
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# @file File
|
||||
# @brief Functions for handling files.
|
||||
|
||||
# @description Create temporary file.
|
||||
# Function creates temporary file with random name. The temporary file will be deleted when script finishes.
|
||||
#
|
||||
# @example
|
||||
# echo "$(file::make_temp_file)"
|
||||
# #Output
|
||||
# tmp.vgftzy
|
||||
#
|
||||
# @noargs
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 1 If failed to create temp file.
|
||||
#
|
||||
# @stdout file name of temporary file created.
|
||||
file::make_temp_file() {
|
||||
declare temp_file
|
||||
type -p mktemp &> /dev/null && { temp_file="$(mktemp -u)" || temp_file="${PWD}/$((RANDOM * 2)).LOG"; }
|
||||
trap 'rm -f "${temp_file}"' EXIT
|
||||
printf "%s" "${temp_file}"
|
||||
}
|
||||
|
||||
# @description Create temporary directory.
|
||||
# Function creates temporary directory with random name. The temporary directory will be deleted when script finishes.
|
||||
#
|
||||
# @example
|
||||
# echo "$(utility::make_temp_dir)"
|
||||
# #Output
|
||||
# tmp.rtfsxy
|
||||
#
|
||||
# @arg $1 string Temporary directory prefix
|
||||
# @arg $2 string Flag to auto remove directory on exit trap (true)
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 1 If failed to create temp directory.
|
||||
# @exitcode 2 Missing arguments.
|
||||
#
|
||||
# @stdout directory name of temporary directory created.
|
||||
file::make_temp_dir() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare temp_dir prefix="${1}" trap_rm="${2}"
|
||||
temp_dir=$(mktemp -d 2>/dev/null || mktemp -d -t "${prefix}")
|
||||
if [[ -n "${trap_rm}" ]]; then
|
||||
trap 'rm -rf "${temp_dir}"' EXIT
|
||||
fi
|
||||
printf "%s" "${temp_dir}"
|
||||
}
|
||||
|
||||
# @description Get only the filename from string path.
|
||||
#
|
||||
# @example
|
||||
# echo "$(file::name "/path/to/test.md")"
|
||||
# #Output
|
||||
# test.md
|
||||
#
|
||||
# @arg $1 string path.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout name of the file with extension.
|
||||
file::name() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
printf "%s" "${1##*/}"
|
||||
}
|
||||
|
||||
# @description Get the basename of file from file name.
|
||||
#
|
||||
# @example
|
||||
# echo "$(file::basename "/path/to/test.md")"
|
||||
# #Output
|
||||
# test
|
||||
#
|
||||
# @arg $1 string path.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout basename of the file.
|
||||
file::basename() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
|
||||
declare file basename
|
||||
file="${1##*/}"
|
||||
basename="${file%.*}"
|
||||
|
||||
printf "%s" "${basename}"
|
||||
}
|
||||
|
||||
# @description Get the extension of file from file name.
|
||||
#
|
||||
# @example
|
||||
# echo "$(file::extension "/path/to/test.md")"
|
||||
# #Output
|
||||
# md
|
||||
#
|
||||
# @arg $1 string path.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 1 If no extension is found in the filename.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout extension of the file.
|
||||
file::extension() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare file extension
|
||||
file="${1##*/}"
|
||||
extension="${file##*.}"
|
||||
[[ "${file}" = "${extension}" ]] && return 1
|
||||
|
||||
printf "%s" "${extension}"
|
||||
}
|
||||
|
||||
# @description Get directory name from file path.
|
||||
#
|
||||
# @example
|
||||
# echo "$(file::dirname "/path/to/test.md")"
|
||||
# #Output
|
||||
# /path/to
|
||||
#
|
||||
# @arg $1 string path.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout directory path.
|
||||
file::dirname() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
|
||||
declare tmp=${1:-.}
|
||||
|
||||
[[ ${tmp} != *[!/]* ]] && { printf '/\n' && return; }
|
||||
tmp="${tmp%%"${tmp##*[!/]}"}"
|
||||
|
||||
[[ ${tmp} != */* ]] && { printf '.\n' && return; }
|
||||
tmp=${tmp%/*} && tmp="${tmp%%"${tmp##*[!/]}"}"
|
||||
|
||||
printf '%s' "${tmp:-/}"
|
||||
}
|
||||
|
||||
# @description Get absolute path of file or directory.
|
||||
#
|
||||
# @example
|
||||
# file::full_path "../path/to/file.md"
|
||||
# #Output
|
||||
# /home/labbots/docs/path/to/file.md
|
||||
#
|
||||
# @arg $1 string relative or absolute path to file/direcotry.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 1 If file/directory does not exist.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout Absolute path to file/directory.
|
||||
file::full_path() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare input="${1}"
|
||||
if [[ -f ${input} ]]; then
|
||||
printf "%s/%s\n" "$(cd "$(file::dirname "${input}")" && pwd)" "${input##*/}"
|
||||
elif [[ -d ${input} ]]; then
|
||||
printf "%s\n" "$(cd "${input}" && pwd)"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# @description Get mime type of provided input.
|
||||
#
|
||||
# @example
|
||||
# file::mime_type "../src/file.sh"
|
||||
# #Output
|
||||
# application/x-shellscript
|
||||
#
|
||||
# @arg $1 string relative or absolute path to file/directory.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 1 If file/directory does not exist.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
# @exitcode 3 If file or mimetype command not found in system.
|
||||
#
|
||||
# @stdout mime type of file/directory.
|
||||
file::mime_type() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
declare mime_type
|
||||
if [[ -f "${1}" ]] || [[ -d "${1}" ]]; then
|
||||
if type -p mimetype &> /dev/null; then
|
||||
mime_type=$(mimetype --output-format %m "${1}")
|
||||
elif type -p file &> /dev/null; then
|
||||
mime_type=$(file --brief --mime-type "${1}")
|
||||
else
|
||||
return 3
|
||||
fi
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
printf "%s" "${mime_type}"
|
||||
}
|
||||
|
||||
# @description Search if a given pattern is found in file.
|
||||
#
|
||||
# @example
|
||||
# file::contains_text "./file.sh" "^[ @[:alpha:]]*"
|
||||
# file::contains_text "./file.sh" "@file"
|
||||
# #Output
|
||||
# 0
|
||||
#
|
||||
# @arg $1 string relative or absolute path to file/directory.
|
||||
# @arg $2 string search key or regular expression.
|
||||
#
|
||||
# @exitcode 0 If given search parameter is found in file.
|
||||
# @exitcode 1 If search paramter not found in file.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
file::contains_text() {
|
||||
[[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
|
||||
declare -r file="$1"
|
||||
declare -r text="$2"
|
||||
grep -q "$text" "$file"
|
||||
}
|
||||
183
functions/bash-utility-master/src/format.sh
Executable file
183
functions/bash-utility-master/src/format.sh
Executable file
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# @file Format
|
||||
# @brief Functions to format provided input.
|
||||
|
||||
# @internal
|
||||
# @description Initialisation script when the code is sourced.
|
||||
#
|
||||
# @noargs
|
||||
__init(){
|
||||
_check_terminal_window_size
|
||||
}
|
||||
|
||||
# @internal
|
||||
# @description Checks the terminal window size, if necessary, updates the values of LINES and COLUMNS.
|
||||
#
|
||||
# @noargs
|
||||
_check_terminal_window_size() {
|
||||
shopt -s checkwinsize && (: && :)
|
||||
trap 'shopt -s checkwinsize; (:;:)' SIGWINCH
|
||||
}
|
||||
# @description Format seconds to human readable format.
|
||||
#
|
||||
# @example
|
||||
# echo "$(format::human_readable_seconds "356786")"
|
||||
# #Output
|
||||
# 4 days 3 hours 6 minute(s) and 26 seconds
|
||||
#
|
||||
# @arg $1 int number of seconds.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout formatted time string.
|
||||
format::human_readable_seconds() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
|
||||
declare T="${1}"
|
||||
declare DAY="$((T / 60 / 60 / 24))" HR="$((T / 60 / 60 % 24))" MIN="$((T / 60 % 60))" SEC="$((T % 60))"
|
||||
[[ ${DAY} -gt 0 ]] && printf '%d days ' "${DAY}"
|
||||
[[ ${HR} -gt 0 ]] && printf '%d hours ' "${HR}"
|
||||
[[ ${MIN} -gt 0 ]] && printf '%d minute(s) ' "${MIN}"
|
||||
[[ ${DAY} -gt 0 || ${HR} -gt 0 || ${MIN} -gt 0 ]] && printf 'and '
|
||||
printf '%d seconds\n' "${SEC}"
|
||||
}
|
||||
|
||||
# @description Format bytes to human readable format.
|
||||
#
|
||||
# @example
|
||||
# echo "$(format::bytes_to_human "2250")"
|
||||
# #Output
|
||||
# 2.19 KB
|
||||
#
|
||||
# @arg $1 int size in bytes.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout formatted file size string.
|
||||
format::bytes_to_human() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2
|
||||
|
||||
declare b=${1:-0} d='' s=0 S=(Bytes {K,M,G,T,P,E,Y,Z}B)
|
||||
while ((b > 1024)); do
|
||||
d="$(printf ".%02d" $((b % 1024 * 100 / 1024)))"
|
||||
b=$((b / 1024)) && ((s++))
|
||||
done
|
||||
printf "%s\n" "${b}${d} ${S[${s}]}"
|
||||
}
|
||||
|
||||
# @description Remove Ansi escape sequences from given text.
|
||||
#
|
||||
# @example
|
||||
# format::strip_ansi "\e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text.\e(B\e[m"
|
||||
# #Output
|
||||
# This is bold red text.This is green text.
|
||||
#
|
||||
# @arg $1 string Input text to be ansi stripped.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
#
|
||||
# @stdout Ansi stripped text.
|
||||
format::strip_ansi() {
|
||||
declare tmp esc tpa re
|
||||
tmp="${1}"
|
||||
esc=$(printf "\x1b")
|
||||
tpa=$(printf "\x28")
|
||||
re="(.*)${esc}[\[${tpa}][0-9]*;*[mKB](.*)"
|
||||
while [[ "${tmp}" =~ $re ]]; do
|
||||
tmp="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
|
||||
done
|
||||
printf "%s" "${tmp}"
|
||||
}
|
||||
|
||||
# @description Prints the given text to centre of terminal.
|
||||
#
|
||||
# @example
|
||||
# format::text_center "This text is in centre of the terminal." "-"
|
||||
#
|
||||
# @arg $1 string Text to be printed.
|
||||
# @arg $2 string Filler symbol to be added to prefix and suffix of the text (optional). Defaults to space as filler.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout formatted text.
|
||||
format::text_center() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
|
||||
|
||||
declare input="${1}" symbol="${2:- }" filler out no_ansi_out
|
||||
no_ansi_out=$(format::strip_ansi "$input")
|
||||
declare -i str_len=${#no_ansi_out}
|
||||
declare -i filler_len="$(((COLUMNS - str_len) / 2))"
|
||||
|
||||
[[ -n "${symbol}" ]] && symbol="${symbol:0:1}"
|
||||
for ((i = 0; i < filler_len; i++)); do
|
||||
filler+="${symbol}"
|
||||
done
|
||||
|
||||
out="${filler}${input}${filler}"
|
||||
[[ $(((COLUMNS - str_len) % 2)) -ne 0 ]] && out+="${symbol}"
|
||||
printf "%s" "${out}"
|
||||
}
|
||||
|
||||
# @description Format String to print beautiful report.
|
||||
#
|
||||
# @example
|
||||
# format::report "Initialising mission state" "Success"
|
||||
# #Output
|
||||
# Initialising mission state ....................................................................[ Success ]
|
||||
#
|
||||
# @arg $1 string Text to be printed on the left.
|
||||
# @arg $2 string Text to be printed within the square brackets.
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout formatted text.
|
||||
format::report() {
|
||||
[[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
|
||||
|
||||
declare symbol="." to_print y hl hlout out
|
||||
declare input1="${1} " input2="${2}"
|
||||
input2="[ $input2 ]"
|
||||
to_print="$((COLUMNS * 60 / 100))"
|
||||
y=$(( to_print - ( ${#input1} + ${#input2} ) ))
|
||||
hl="$(printf '%*s' $y '')"
|
||||
hlout=${hl// /${symbol}}
|
||||
out="${input1}${hlout}${input2}"
|
||||
printf "%s\n" "${out}"
|
||||
}
|
||||
|
||||
# @description Trim given text to width of the terminal window.
|
||||
#
|
||||
# @example
|
||||
# format::trim_text_to_term "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat." "This is part of second sentence."
|
||||
# #Output
|
||||
# Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..This is part of second sentence.
|
||||
#
|
||||
# @arg $1 string Text of first sentence.
|
||||
# @arg $2 string Text of second sentence (optional).
|
||||
#
|
||||
# @exitcode 0 If successful.
|
||||
# @exitcode 2 Function missing arguments.
|
||||
#
|
||||
# @stdout trimmed text.
|
||||
format::trim_text_to_term() {
|
||||
[[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1
|
||||
|
||||
declare to_print out input1="$1" input2="$2"
|
||||
if [[ $# = 1 ]]; then
|
||||
to_print="$((COLUMNS * 93 / 100))"
|
||||
{ [[ ${#input1} -gt ${to_print} ]] && out="${input1:0:to_print}.."; } || { out="$input1"; }
|
||||
else
|
||||
to_print="$((COLUMNS * 40 / 100))"
|
||||
{ [[ ${#input1} -gt ${to_print} ]] && out+=" ${input1:0:to_print}.."; } || { out+=" $input1"; }
|
||||
to_print="$((COLUMNS * 53 / 100))"
|
||||
{ [[ ${#input2} -gt ${to_print} ]] && out+="${input2:0:to_print}.. "; } || { out+="$input2 "; }
|
||||
fi
|
||||
printf "%s" "$out"
|
||||
}
|
||||
|
||||
__init
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user