├── .editorconfig ├── .gitignore ├── .remarkrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bash_utility.sh ├── bin ├── bashdoc.awk └── generate_readme.sh ├── image ├── bash-utility.png └── logo.png └── src ├── array.sh ├── check.sh ├── collection.sh ├── date.sh ├── debug.sh ├── file.sh ├── format.sh ├── interaction.sh ├── json.sh ├── misc.sh ├── os.sh ├── string.sh ├── terminal.sh ├── validation.sh └── variable.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | # for shfmt 14 | [*.sh] 15 | indent_style = space 16 | indent_size = 4 17 | shell_variant = bash 18 | switch_case_indent = true 19 | space_redirects = true 20 | 21 | [*.md] 22 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /tmp 2 | gh-pages 3 | hugo-docs 4 | -------------------------------------------------------------------------------- /.remarkrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "remark-preset-lint-markdown-style-guide", 4 | ["remark-lint-list-item-spacing", false], 5 | ["remark-lint-maximum-line-length", false], 6 | ["remark-lint-no-duplicate-headings", false] 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at 72 | 73 | For answers to common questions about this code of conduct, see 74 | 75 | 76 | [homepage]: https://www.contributor-covenant.org 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Bash-Utility 2 | 3 | :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: 4 | 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. 5 | 6 | ## Table of Contents 7 | - [Code Contributions](#code-contributions) 8 | - [Code Guidelines](#code-guidelines) 9 | - [Styleguide](#styleguide) 10 | - [Bashdoc guideline](#bashdoc-guideline) 11 | - [Documentation](#documentation) 12 | - [Commit Guidelines](#commit-guidelines) 13 | - [Pull Request Guidelines](#pull-request-guidelines) 14 | - [Contact](#contact) 15 | 16 | ## Code Contributions 17 | 18 | Great, the more, the merrier. 19 | 20 | Sane code contributions are always welcome, whether to the code or documentation. 21 | 22 | Before making a pull request, make sure to follow below guidelines: 23 | 24 | ### Code Guidelines 25 | 26 | #### Styleguide 27 | 28 | - Variable names must be meaningful and self-documenting. 29 | - Long variable names must be structured by underscores to improve legibility. 30 | - Global variables and constants must be ALL CAPS with underscores. (eg., INPUT_FILE) 31 | - local variables used within functions must be all lower case with underscores ( only if required ). (eg., input_data) 32 | - Variable names can be alphanumeric with underscores. No special characters in variable names. 33 | - Variables name must not start with number. 34 | - Variables within function must be declared. So the scope of variable is restricted to the function. 35 | - Avoid accessing global variables within functions. 36 | - Function names must be all lower case with underscores to seperate words (snake_case). 37 | - Function name must start with section name followed by 2 colons and then the function name (eg., `array::contains()`) 38 | - Try using bash builtins and string substitution as much as possible. 39 | - Use printf everywhere instead of echo. 40 | - Before adding a new logic, be sure to check the existing code. 41 | - Make sure to add the function in appropriate section based on its operation. 42 | - Use [shfmt](https://github.com/mvdan/sh) to format the script. Use below command: 43 | 44 | ```shell 45 | shfmt upload.sh 46 | ``` 47 | 48 | The repo already provides the .editorconfig file, which shfmt reads, so no need for extra flags. 49 | You can also install shfmt for various editors, refer their repo for information. 50 | Note: This is strictly necessary to maintain consistency, do not skip. 51 | 52 | - Script should pass all [shellcheck](https://www.shellcheck.net/) warnings, if not, then disable the warning and give a valid reason. 53 | 54 | #### Bashdoc guideline 55 | 56 | The documentation is generated based on the function documentation within the script file. So ensure to follow the style so the documentation is 57 | properly generated by the generator. 58 | 59 | Follow the below bashdoc template to add function introductory comment. 60 | 61 | ```bash 62 | # @description Multiline description goes here and 63 | # there 64 | # 65 | # @example 66 | # sample::function a b c 67 | # echo 123 68 | # 69 | # @arg $1 string Some arg. 70 | # @arg $2 any Rest of arguments. 71 | # 72 | # @noargs 73 | # 74 | # @exitcode 0 If successfull. 75 | # @exitcode >0 On failure 76 | # @exitcode 5 On some error. 77 | # 78 | # @stdout Path to something. 79 | # 80 | # @see sample::other_function(() 81 | sample::function() { 82 | } 83 | ``` 84 | 85 | - Each function must have a description detailing what the function does and a sample usage example to show how the function can be used. 86 | - specify whether the function accepts args or no args by specifying @arg or @noargs tag in the comment. 87 | - Make sure to document the exitcode emitted by the function. 88 | - If the function is similar to other function add a reference to function using @see tag. 89 | 90 | ### Documentation 91 | 92 | - Refrain from making unnecessary newlines or whitespace. 93 | - Use pure markdown as much as possible, html is accepted but shouldn't be a priority. 94 | - The markdown must pass RemarkLint checks. 95 | - 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. 96 | 97 | ```bash 98 | ./bin/generate_readme.sh -f README.md -s src/ 99 | ``` 100 | 101 | ### Commit Guidelines 102 | 103 | 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. 104 | 105 | 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. 106 | 107 | 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. 108 | 109 | Before committing check for unnecessary whitespace with `git diff --check`. 110 | 111 | ### Pull Request Guidelines 112 | 113 | The following guidelines will increase the likelihood that your pull request will get accepted: 114 | 115 | - Follow the commit and code guidelines. 116 | - Keep the patches on topic and focused. 117 | - Try to avoid unnecessary formatting and clean-up where reasonable. 118 | 119 | A pull request should contain the following: 120 | 121 | - At least one commit (all of which should follow the Commit Guidelines). 122 | - Title that summarises the issue/feature. 123 | - Description that briefly summarises the changes. 124 | 125 | After submitting a pull request, you should get a response within 7 days. If you do not, don't hesitate to ping the thread. 126 | 127 | ## Contact 128 | 129 | For further inquiries, you can contact the developer by opening an issue on the repository. 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 labbots 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Bash Utility

2 | 3 |

4 | Stars 5 | License 6 | 7 |

8 |

9 | Gh-pages Status 10 | Website 11 |

12 |

13 | Total number of Library functions 14 |

15 |

16 | 17 |

18 | Bash library which provides utility functions and helpers for functional programming in Bash. 19 | 20 | Detailed documentation is available at 21 | 22 | 23 | 24 | ## Table of Contents 25 | 26 | - [Installation](#installation) 27 | - [Method 1 - Git Submodules](#method-1---git-submodules) 28 | - [Method 2 - Git Clone](#method-2---git-clone) 29 | - [Method 3 - Direct Download](#method-3---direct-download) 30 | - [Usage](#usage) 31 | - [Array](#array) 32 | - [array::contains()](#arraycontains) 33 | - [array::dedupe()](#arraydedupe) 34 | - [array::is_empty()](#arrayis_empty) 35 | - [array::join()](#arrayjoin) 36 | - [array::reverse()](#arrayreverse) 37 | - [array::random_element()](#arrayrandom_element) 38 | - [array::sort()](#arraysort) 39 | - [array::rsort()](#arrayrsort) 40 | - [array::bsort()](#arraybsort) 41 | - [array::merge()](#arraymerge) 42 | - [Check](#check) 43 | - [check::command_exists()](#checkcommand_exists) 44 | - [check::is_sudo()](#checkis_sudo) 45 | - [Collection](#collection) 46 | - [collection::each()](#collectioneach) 47 | - [collection::every()](#collectionevery) 48 | - [collection::filter()](#collectionfilter) 49 | - [collection::find()](#collectionfind) 50 | - [collection::invoke()](#collectioninvoke) 51 | - [collection::map()](#collectionmap) 52 | - [collection::reject()](#collectionreject) 53 | - [collection::some()](#collectionsome) 54 | - [Date](#date) 55 | - [date::now()](#datenow) 56 | - [date::epoc()](#dateepoc) 57 | - [date::add_days_from()](#dateadd_days_from) 58 | - [date::add_months_from()](#dateadd_months_from) 59 | - [date::add_years_from()](#dateadd_years_from) 60 | - [date::add_weeks_from()](#dateadd_weeks_from) 61 | - [date::add_hours_from()](#dateadd_hours_from) 62 | - [date::add_minutes_from()](#dateadd_minutes_from) 63 | - [date::add_seconds_from()](#dateadd_seconds_from) 64 | - [date::add_days()](#dateadd_days) 65 | - [date::add_months()](#dateadd_months) 66 | - [date::add_years()](#dateadd_years) 67 | - [date::add_weeks()](#dateadd_weeks) 68 | - [date::add_hours()](#dateadd_hours) 69 | - [date::add_minutes()](#dateadd_minutes) 70 | - [date::add_seconds()](#dateadd_seconds) 71 | - [date::sub_days_from()](#datesub_days_from) 72 | - [date::sub_months_from()](#datesub_months_from) 73 | - [date::sub_years_from()](#datesub_years_from) 74 | - [date::sub_weeks_from()](#datesub_weeks_from) 75 | - [date::sub_hours_from()](#datesub_hours_from) 76 | - [date::sub_minutes_from()](#datesub_minutes_from) 77 | - [date::sub_seconds_from()](#datesub_seconds_from) 78 | - [date::sub_days()](#datesub_days) 79 | - [date::sub_months()](#datesub_months) 80 | - [date::sub_years()](#datesub_years) 81 | - [date::sub_weeks()](#datesub_weeks) 82 | - [date::sub_hours()](#datesub_hours) 83 | - [date::sub_minutes()](#datesub_minutes) 84 | - [date::sub_seconds()](#datesub_seconds) 85 | - [date::format()](#dateformat) 86 | - [Debug](#debug) 87 | - [debug::print_array()](#debugprint_array) 88 | - [debug::print_ansi()](#debugprint_ansi) 89 | - [File](#file) 90 | - [file::make_temp_file()](#filemake_temp_file) 91 | - [file::make_temp_dir()](#filemake_temp_dir) 92 | - [file::name()](#filename) 93 | - [file::basename()](#filebasename) 94 | - [file::extension()](#fileextension) 95 | - [file::dirname()](#filedirname) 96 | - [file::full_path()](#filefull_path) 97 | - [file::mime_type()](#filemime_type) 98 | - [file::contains_text()](#filecontains_text) 99 | - [Format](#format) 100 | - [format::human_readable_seconds()](#formathuman_readable_seconds) 101 | - [format::bytes_to_human()](#formatbytes_to_human) 102 | - [format::strip_ansi()](#formatstrip_ansi) 103 | - [format::text_center()](#formattext_center) 104 | - [format::report()](#formatreport) 105 | - [format::trim_text_to_term()](#formattrim_text_to_term) 106 | - [Interaction](#interaction) 107 | - [interaction::prompt_yes_no()](#interactionprompt_yes_no) 108 | - [interaction::prompt_response()](#interactionprompt_response) 109 | - [Json](#json) 110 | - [json::get_value()](#jsonget_value) 111 | - [Miscellaneous](#miscellaneous) 112 | - [misc::check_internet_connection()](#misccheck_internet_connection) 113 | - [misc::get_pid()](#miscget_pid) 114 | - [misc::get_uid()](#miscget_uid) 115 | - [misc::generate_uuid()](#miscgenerate_uuid) 116 | - [Operating System](#operating-system) 117 | - [os::detect_os()](#osdetect_os) 118 | - [os::detect_linux_distro()](#osdetect_linux_distro) 119 | - [os::detect_linux_version()](#osdetect_linux_version) 120 | - [os::detect_mac_version()](#osdetect_mac_version) 121 | - [String](#string) 122 | - [string::trim()](#stringtrim) 123 | - [string::split()](#stringsplit) 124 | - [string::lstrip()](#stringlstrip) 125 | - [string::rstrip()](#stringrstrip) 126 | - [string::to_lower()](#stringto_lower) 127 | - [string::to_upper()](#stringto_upper) 128 | - [string::contains()](#stringcontains) 129 | - [string::starts_with()](#stringstarts_with) 130 | - [string::ends_with()](#stringends_with) 131 | - [string::regex()](#stringregex) 132 | - [Terminal](#terminal) 133 | - [terminal::is_term()](#terminalis_term) 134 | - [terminal::detect_profile()](#terminaldetect_profile) 135 | - [terminal::clear_line()](#terminalclear_line) 136 | - [Validation](#validation) 137 | - [validation::email()](#validationemail) 138 | - [validation::ipv4()](#validationipv4) 139 | - [validation::ipv6()](#validationipv6) 140 | - [validation::alpha()](#validationalpha) 141 | - [validation::alpha_num()](#validationalpha_num) 142 | - [validation::alpha_dash()](#validationalpha_dash) 143 | - [validation::version_comparison()](#validationversion_comparison) 144 | - [Variable](#variable) 145 | - [variable::is_array()](#variableis_array) 146 | - [variable::is_numeric()](#variableis_numeric) 147 | - [variable::is_int()](#variableis_int) 148 | - [variable::is_float()](#variableis_float) 149 | - [variable::is_bool()](#variableis_bool) 150 | - [variable::is_true()](#variableis_true) 151 | - [variable::is_false()](#variableis_false) 152 | - [variable::is_empty_or_null()](#variableis_empty_or_null) 153 | - [Inspired By](#inspired-by) 154 | - [License](#license) 155 | 156 | 157 | ## Installation 158 | The script can be installed and sourced using following methods. 159 | 160 | ### Method 1 - Git Submodules 161 | If the library is used inside a git project then git submodules can be used to install the library to the project. 162 | Following command will initialize git submodule and download the library to `./vendor/bash-utility` folder. 163 | 164 | ```shell 165 | git submodule init 166 | git submodule add -b master https://github.com/labbots/bash-utility vendor/bash-utility 167 | ``` 168 | 169 | To Update submodules to latest code execute the following command. 170 | 171 | ```shell 172 | git submodule update --rebase --remote 173 | ``` 174 | Once the submodule is added or updated, make sure to commit changes to your repository. 175 | 176 | ```shell 177 | git add . 178 | git commit -m 'Added/updated bash-utility library.' 179 | ``` 180 | **Note:** When cloning your repository, use `--recurse-submodules` flag to `git clone` command to install the git sub modules. 181 | 182 | ### Method 2 - Git Clone 183 | If you don't want to use git submodules, you can use `git clone` to download library and then move the files to desired location manually. 184 | 185 | The below command will clone the repository to `vendor/bash-utility` folder in current working directory. 186 | 187 | ```shell 188 | git clone https://github.com/labbots/bash-utility.git ./vendor/bash-utility 189 | ``` 190 | ### Method 3 - Direct Download 191 | If you do not have git installed, you can download the archive of the latest version of the library. Extract the zip file to appropriate folder by following the below command. 192 | 193 | ```shell 194 | wget https://github.com/labbots/bash-utility/archive/master.zip 195 | unzip -q master.zip -d tmp 196 | mkdir -p vendor/bash-utility 197 | mv tmp/bash-utility-master vendor/bash-utility 198 | rm tmp 199 | ``` 200 | 201 | ## Usage 202 | Bash utility functions can be used by simply sourcing the library script file to your own script. 203 | To access all the functions within the bash-utility library, you could import the main bash file as follows. 204 | 205 | ```shell 206 | source "vendor/bash-utility/bash-utility.sh" 207 | ``` 208 | 209 | You can also only use the necessary library functions by only importing the required function files. 210 | 211 | ```shell 212 | source "vendor/bash-utility/src/array.sh" 213 | ``` 214 | 215 | 216 | 217 | ## Array 218 | 219 | Functions for array operations and manipulations. 220 | 221 | ### array::contains() 222 | 223 | Check if item exists in the given array. 224 | 225 | #### Arguments 226 | 227 | - **$1** (mixed): Item to search (needle). 228 | - **$2** (array): array to be searched (haystack). 229 | 230 | #### Exit codes 231 | 232 | - **0**: If successful. 233 | - **1**: If no match found in the array. 234 | - **2**: Function missing arguments. 235 | 236 | #### Example 237 | 238 | ```bash 239 | array=("a" "b" "c") 240 | array::contains "c" ${array[@]} 241 | #Output 242 | 0 243 | ``` 244 | 245 | ### array::dedupe() 246 | 247 | Remove duplicate items from the array. 248 | 249 | #### Arguments 250 | 251 | - **$1** (array): Array to be deduped. 252 | 253 | #### Exit codes 254 | 255 | - **0**: If successful. 256 | - **2**: Function missing arguments. 257 | 258 | #### Output on stdout 259 | 260 | - Deduplicated array. 261 | 262 | #### Example 263 | 264 | ```bash 265 | array=("a" "b" "a" "c") 266 | printf "%s" "$(array::dedupe ${array[@]})" 267 | #Output 268 | a 269 | b 270 | c 271 | ``` 272 | 273 | ### array::is_empty() 274 | 275 | Check if a given array is empty. 276 | 277 | #### Arguments 278 | 279 | - **$1** (array): Array to be checked. 280 | 281 | #### Exit codes 282 | 283 | - **0**: If the given array is empty. 284 | - **2**: If the given array is not empty. 285 | 286 | #### Example 287 | 288 | ```bash 289 | array=("a" "b" "c" "d") 290 | array::is_empty "${array[@]}" 291 | ``` 292 | 293 | ### array::join() 294 | 295 | Join array elements with a string. 296 | 297 | #### Arguments 298 | 299 | - **$1** (string): String to join the array elements (glue). 300 | - **$2** (array): array to be joined with glue string. 301 | 302 | #### Exit codes 303 | 304 | - **0**: If successful. 305 | - **2**: Function missing arguments. 306 | 307 | #### Output on stdout 308 | 309 | - String containing a string representation of all the array elements in the same order,with the glue string between each element. 310 | 311 | #### Example 312 | 313 | ```bash 314 | array=("a" "b" "c" "d") 315 | printf "%s" "$(array::join "," "${array[@]}")" 316 | #Output 317 | a,b,c,d 318 | printf "%s" "$(array::join "" "${array[@]}")" 319 | #Output 320 | abcd 321 | ``` 322 | 323 | ### array::reverse() 324 | 325 | Return an array with elements in reverse order. 326 | 327 | #### Arguments 328 | 329 | - **$1** (array): The input array. 330 | 331 | #### Exit codes 332 | 333 | - **0**: If successful. 334 | - **2**: Function missing arguments. 335 | 336 | #### Output on stdout 337 | 338 | - The reversed array. 339 | 340 | #### Example 341 | 342 | ```bash 343 | array=(1 2 3 4 5) 344 | printf "%s" "$(array::reverse "${array[@]}")" 345 | #Output 346 | 5 4 3 2 1 347 | ``` 348 | 349 | ### array::random_element() 350 | 351 | Returns a random item from the array. 352 | 353 | #### Arguments 354 | 355 | - **$1** (array): The input array. 356 | 357 | #### Exit codes 358 | 359 | - **0**: If successful. 360 | - **2**: Function missing arguments. 361 | 362 | #### Output on stdout 363 | 364 | - Random item out of the array. 365 | 366 | #### Example 367 | 368 | ```bash 369 | array=("a" "b" "c" "d") 370 | printf "%s\n" "$(array::random_element "${array[@]}")" 371 | #Output 372 | c 373 | ``` 374 | 375 | ### array::sort() 376 | 377 | Sort an array from lowest to highest. 378 | 379 | #### Arguments 380 | 381 | - **$1** (array): The input array. 382 | 383 | #### Exit codes 384 | 385 | - **0**: If successful. 386 | - **2**: Function missing arguments. 387 | 388 | #### Output on stdout 389 | 390 | - sorted array. 391 | 392 | #### Example 393 | 394 | ```bash 395 | sarr=("a c" "a" "d" 2 1 "4 5") 396 | array::array_sort "${sarr[@]}" 397 | #Output 398 | 1 399 | 2 400 | 4 5 401 | a 402 | a c 403 | d 404 | ``` 405 | 406 | ### array::rsort() 407 | 408 | Sort an array in reverse order (highest to lowest). 409 | 410 | #### Arguments 411 | 412 | - **$1** (array): The input array. 413 | 414 | #### Exit codes 415 | 416 | - **0**: If successful. 417 | - **2**: Function missing arguments. 418 | 419 | #### Output on stdout 420 | 421 | - reverse sorted array. 422 | 423 | #### Example 424 | 425 | ```bash 426 | sarr=("a c" "a" "d" 2 1 "4 5") 427 | array::array_sort "${sarr[@]}" 428 | #Output 429 | d 430 | a c 431 | a 432 | 4 5 433 | 2 434 | 1 435 | ``` 436 | 437 | ### array::bsort() 438 | 439 | Bubble sort an integer array from lowest to highest. 440 | This sort does not work on string array. 441 | 442 | #### Arguments 443 | 444 | - **$1** (array): The input array. 445 | 446 | #### Exit codes 447 | 448 | - **0**: If successful. 449 | - **2**: Function missing arguments. 450 | 451 | #### Output on stdout 452 | 453 | - bubble sorted array. 454 | 455 | #### Example 456 | 457 | ```bash 458 | iarr=(4 5 1 3) 459 | array::bsort "${iarr[@]}" 460 | #Output 461 | 1 462 | 3 463 | 4 464 | 5 465 | ``` 466 | 467 | ### array::merge() 468 | 469 | Merge two arrays. 470 | Pass the variable name of the array instead of value of the variable. 471 | 472 | #### Arguments 473 | 474 | - **$1** (string): variable name of first array. 475 | - **$2** (string): variable name of second array. 476 | 477 | #### Exit codes 478 | 479 | - **0**: If successful. 480 | - **2**: Function missing arguments. 481 | 482 | #### Output on stdout 483 | 484 | - Merged array. 485 | 486 | #### Example 487 | 488 | ```bash 489 | a=("a" "c") 490 | b=("d" "c") 491 | array::merge "a[@]" "b[@]" 492 | #Output 493 | a 494 | c 495 | d 496 | c 497 | ``` 498 | 499 | ## Check 500 | 501 | Helper functions. 502 | 503 | ### check::command_exists() 504 | 505 | Check if the command exists in the system. 506 | 507 | #### Arguments 508 | 509 | - **$1** (string): Command name to be searched. 510 | 511 | #### Exit codes 512 | 513 | - **0**: If the command exists. 514 | - **1**: If the command does not exist. 515 | - **2**: Function missing arguments. 516 | 517 | #### Example 518 | 519 | ```bash 520 | check::command_exists "tput" 521 | ``` 522 | 523 | ### check::is_sudo() 524 | 525 | Check if the script is executed with sudo privilege. 526 | 527 | *Function has no arguments.* 528 | 529 | #### Exit codes 530 | 531 | - **0**: If the script is executed with root privilege. 532 | - **1**: If the script is not executed with root privilege 533 | 534 | #### Example 535 | 536 | ```bash 537 | check::is_sudo 538 | ``` 539 | 540 | ## Collection 541 | 542 | (Experimental) Functions to iterates over a list of elements, yielding each in turn to an iteratee function. 543 | 544 | ### collection::each() 545 | 546 | Iterates over elements of collection and invokes iteratee for each element. 547 | Input to the function can be a pipe output, here-string or file. 548 | 549 | #### Arguments 550 | 551 | - **$1** (string): Iteratee function. 552 | 553 | #### Exit codes 554 | 555 | - **0**: If successful. 556 | - **2**: Function missing arguments. 557 | - other exitcode returned by iteratee. 558 | 559 | #### Output on stdout 560 | 561 | - Output of iteratee function. 562 | 563 | #### Example 564 | 565 | ```bash 566 | test_func(){ 567 | printf "print value: %s\n" "$1" 568 | return 0 569 | } 570 | arr1=("a b" "c d" "a" "d") 571 | printf "%s\n" "${arr1[@]}" | collection::each "test_func" 572 | collection::each "test_func" < <(printf "%s\n" "${arr1[@]}") #alternative approach 573 | #output 574 | print value: a b 575 | print value: c d 576 | print value: a 577 | print value: d 578 | ``` 579 | 580 | #### Example 581 | 582 | ```bash 583 | # If other function from this library is already used to process the array. 584 | # Then following method could be used to pass the array to the function. 585 | out=("$(array::dedupe "${arr1[@]}")") 586 | collection::each "test_func" <<< "${out[@]}" 587 | ``` 588 | 589 | ### collection::every() 590 | 591 | Checks if iteratee function returns truthy for all elements of collection. Iteration is stopped once predicate returns false. 592 | Input to the function can be a pipe output, here-string or file. 593 | 594 | #### Arguments 595 | 596 | - **$1** (string): Iteratee function. 597 | 598 | #### Exit codes 599 | 600 | - **0**: If successful. 601 | - **1**: If iteratee function fails. 602 | - **2**: Function missing arguments. 603 | 604 | #### Example 605 | 606 | ```bash 607 | arri=("1" "2" "3" "4") 608 | printf "%s\n" "${arri[@]}" | collection::every "variable::is_numeric" 609 | ``` 610 | 611 | ### collection::filter() 612 | 613 | Iterates over elements of array, returning all elements where iteratee returns true. 614 | Input to the function can be a pipe output, here-string or file. 615 | 616 | #### Arguments 617 | 618 | - **$1** (string): Iteratee function. 619 | 620 | #### Exit codes 621 | 622 | - **0**: If successful. 623 | - **2**: Function missing arguments. 624 | 625 | #### Output on stdout 626 | 627 | - array values matching the iteratee function. 628 | 629 | #### Example 630 | 631 | ```bash 632 | arri=("1" "2" "3" "a") 633 | printf "%s\n" "${arri[@]}" | collection::filter "variable::is_numeric" 634 | #output 635 | 1 636 | 2 637 | 3 638 | ``` 639 | 640 | ### collection::find() 641 | 642 | Iterates over elements of collection, returning the first element where iteratee returns true. 643 | Input to the function can be a pipe output, here-string or file. 644 | 645 | #### Arguments 646 | 647 | - **$1** (string): Iteratee function. 648 | 649 | #### Exit codes 650 | 651 | - **0**: If successful. 652 | - **1**: If no match found. 653 | - **2**: Function missing arguments. 654 | 655 | #### Output on stdout 656 | 657 | - first array value matching the iteratee function. 658 | 659 | #### Example 660 | 661 | ```bash 662 | arr=("1" "2" "3" "a") 663 | check_a(){ 664 | [[ "$1" = "a" ]] 665 | } 666 | printf "%s\n" "${arr[@]}" | collection::find "check_a" 667 | #Output 668 | a 669 | ``` 670 | 671 | ### collection::invoke() 672 | 673 | Invokes the iteratee with each element passed as argument to the iteratee. 674 | Input to the function can be a pipe output, here-string or file. 675 | 676 | #### Arguments 677 | 678 | - **$1** (string): Iteratee function. 679 | 680 | #### Exit codes 681 | 682 | - **0**: If successful. 683 | - **2**: Function missing arguments. 684 | - other exitcode returned by iteratee. 685 | 686 | #### Output on stdout 687 | 688 | - Output from the iteratee function. 689 | 690 | #### Example 691 | 692 | ```bash 693 | opt=("-a" "-l") 694 | printf "%s\n" "${opt[@]}" | collection::invoke "ls" 695 | ``` 696 | 697 | ### collection::map() 698 | 699 | Creates an array of values by running each element in array through iteratee. 700 | Input to the function can be a pipe output, here-string or file. 701 | 702 | #### Arguments 703 | 704 | - **$1** (string): Iteratee function. 705 | 706 | #### Exit codes 707 | 708 | - **0**: If successful. 709 | - **2**: Function missing arguments. 710 | - other exitcode returned by iteratee. 711 | 712 | #### Output on stdout 713 | 714 | - Output result of iteratee on value. 715 | 716 | #### Example 717 | 718 | ```bash 719 | arri=("1" "2" "3") 720 | add_one(){ 721 | i=${1} 722 | i=$(( i + 1 )) 723 | printf "%s\n" "$i" 724 | } 725 | printf "%s\n" "${arri[@]}" | collection::map "add_one" 726 | ``` 727 | 728 | ### collection::reject() 729 | 730 | The opposite of filter function; this method returns the elements of collection that iteratee does not return true. 731 | Input to the function can be a pipe output, here-string or file. 732 | 733 | #### Arguments 734 | 735 | - **$1** (string): Iteratee function. 736 | 737 | #### Exit codes 738 | 739 | - **0**: If successful. 740 | - **2**: Function missing arguments. 741 | 742 | #### Output on stdout 743 | 744 | - array values not matching the iteratee function. 745 | 746 | #### Example 747 | 748 | ```bash 749 | arri=("1" "2" "3" "a") 750 | printf "%s\n" "${arri[@]}" | collection::reject "variable::is_numeric" 751 | #Ouput 752 | a 753 | ``` 754 | 755 | #### See also 756 | 757 | - [collection::filter](#collectionfilter) 758 | 759 | ### collection::some() 760 | 761 | Checks if iteratee returns true for any element of the array. 762 | Input to the function can be a pipe output, here-string or file. 763 | 764 | #### Arguments 765 | 766 | - **$1** (string): Iteratee function. 767 | 768 | #### Exit codes 769 | 770 | - **0**: If match successful. 771 | - **1**: If no match found. 772 | - **2**: Function missing arguments. 773 | 774 | #### Example 775 | 776 | ```bash 777 | arr=("a" "b" "3" "a") 778 | printf "%s\n" "${arr[@]}" | collection::reject "variable::is_numeric" 779 | ``` 780 | 781 | ## Date 782 | 783 | Functions for manipulating dates. 784 | 785 | ### date::now() 786 | 787 | Get current time in unix timestamp. 788 | 789 | *Function has no arguments.* 790 | 791 | #### Exit codes 792 | 793 | - **0**: If successful. 794 | - **1**: If unable to generate timestamp. 795 | 796 | #### Output on stdout 797 | 798 | - current timestamp. 799 | 800 | #### Example 801 | 802 | ```bash 803 | echo "$(date::now)" 804 | #Output 805 | 1591554426 806 | ``` 807 | 808 | ### date::epoc() 809 | 810 | convert datetime string to unix timestamp. 811 | 812 | #### Arguments 813 | 814 | - **$1** (string): date time in any format. 815 | 816 | #### Exit codes 817 | 818 | - **0**: If successful. 819 | - **1**: If unable to generate timestamp. 820 | - **2**: Function missing arguments. 821 | 822 | #### Output on stdout 823 | 824 | - timestamp for specified datetime. 825 | 826 | #### Example 827 | 828 | ```bash 829 | echo "$(date::epoc "2020-07-07 18:38")" 830 | #Output 831 | 1594143480 832 | ``` 833 | 834 | ### date::add_days_from() 835 | 836 | Add number of days from specified timestamp. 837 | If number of days not specified then it defaults to 1 day. 838 | 839 | #### Arguments 840 | 841 | - **$1** (int): unix timestamp. 842 | - **$2** (int): number of days (optional). 843 | 844 | #### Exit codes 845 | 846 | - **0**: If successful. 847 | - **1**: If unable to generate timestamp. 848 | - **2**: Function missing arguments. 849 | 850 | #### Output on stdout 851 | 852 | - timestamp. 853 | 854 | #### Example 855 | 856 | ```bash 857 | echo "$(date::add_days_from "1594143480")" 858 | #Output 859 | 1594229880 860 | ``` 861 | 862 | ### date::add_months_from() 863 | 864 | Add number of months from specified timestamp. 865 | If number of months not specified then it defaults to 1 month. 866 | 867 | #### Arguments 868 | 869 | - **$1** (int): unix timestamp. 870 | - **$2** (int): number of months (optional). 871 | 872 | #### Exit codes 873 | 874 | - **0**: If successful. 875 | - **1**: If unable to generate timestamp. 876 | - **2**: Function missing arguments. 877 | 878 | #### Output on stdout 879 | 880 | - timestamp. 881 | 882 | #### Example 883 | 884 | ```bash 885 | echo "$(date::add_months_from "1594143480")" 886 | #Output 887 | 1596821880 888 | ``` 889 | 890 | ### date::add_years_from() 891 | 892 | Add number of years from specified timestamp. 893 | If number of years not specified then it defaults to 1 year. 894 | 895 | #### Arguments 896 | 897 | - **$1** (int): unix timestamp. 898 | - **$2** (int): number of years (optional). 899 | 900 | #### Exit codes 901 | 902 | - **0**: If successful. 903 | - **1**: If unable to generate timestamp. 904 | - **2**: Function missing arguments. 905 | 906 | #### Output on stdout 907 | 908 | - timestamp. 909 | 910 | #### Example 911 | 912 | ```bash 913 | echo "$(date::add_years_from "1594143480")" 914 | #Output 915 | 1625679480 916 | ``` 917 | 918 | ### date::add_weeks_from() 919 | 920 | Add number of weeks from specified timestamp. 921 | If number of weeks not specified then it defaults to 1 week. 922 | 923 | #### Arguments 924 | 925 | - **$1** (int): unix timestamp. 926 | - **$2** (int): number of weeks (optional). 927 | 928 | #### Exit codes 929 | 930 | - **0**: If successful. 931 | - **1**: If unable to generate timestamp. 932 | - **2**: Function missing arguments. 933 | 934 | #### Output on stdout 935 | 936 | - timestamp. 937 | 938 | #### Example 939 | 940 | ```bash 941 | echo "$(date::add_weeks_from "1594143480")" 942 | #Output 943 | 1594748280 944 | ``` 945 | 946 | ### date::add_hours_from() 947 | 948 | Add number of hours from specified timestamp. 949 | If number of hours not specified then it defaults to 1 hour. 950 | 951 | #### Arguments 952 | 953 | - **$1** (int): unix timestamp. 954 | - **$2** (int): number of hours (optional). 955 | 956 | #### Exit codes 957 | 958 | - **0**: If successful. 959 | - **1**: If unable to generate timestamp. 960 | - **2**: Function missing arguments. 961 | 962 | #### Output on stdout 963 | 964 | - timestamp. 965 | 966 | #### Example 967 | 968 | ```bash 969 | echo "$(date::add_hours_from "1594143480")" 970 | #Output 971 | 1594147080 972 | ``` 973 | 974 | ### date::add_minutes_from() 975 | 976 | Add number of minutes from specified timestamp. 977 | If number of minutes not specified then it defaults to 1 minute. 978 | 979 | #### Arguments 980 | 981 | - **$1** (int): unix timestamp. 982 | - **$2** (int): number of minutes (optional). 983 | 984 | #### Exit codes 985 | 986 | - **0**: If successful. 987 | - **1**: If unable to generate timestamp. 988 | - **2**: Function missing arguments. 989 | 990 | #### Output on stdout 991 | 992 | - timestamp. 993 | 994 | #### Example 995 | 996 | ```bash 997 | echo "$(date::add_minutes_from "1594143480")" 998 | #Output 999 | 1594143540 1000 | ``` 1001 | 1002 | ### date::add_seconds_from() 1003 | 1004 | Add number of seconds from specified timestamp. 1005 | If number of seconds not specified then it defaults to 1 second. 1006 | 1007 | #### Arguments 1008 | 1009 | - **$1** (int): unix timestamp. 1010 | - **$2** (int): number of seconds (optional). 1011 | 1012 | #### Exit codes 1013 | 1014 | - **0**: If successful. 1015 | - **1**: If unable to generate timestamp. 1016 | - **2**: Function missing arguments. 1017 | 1018 | #### Output on stdout 1019 | 1020 | - timestamp. 1021 | 1022 | #### Example 1023 | 1024 | ```bash 1025 | echo "$(date::add_seconds_from "1594143480")" 1026 | #Output 1027 | 1594143481 1028 | ``` 1029 | 1030 | ### date::add_days() 1031 | 1032 | Add number of days from current day timestamp. 1033 | If number of days not specified then it defaults to 1 day. 1034 | 1035 | #### Arguments 1036 | 1037 | - **$1** (int): number of days (optional). 1038 | 1039 | #### Exit codes 1040 | 1041 | - **0**: If successful. 1042 | - **1**: If unable to generate timestamp. 1043 | 1044 | #### Output on stdout 1045 | 1046 | - timestamp. 1047 | 1048 | #### Example 1049 | 1050 | ```bash 1051 | echo "$(date::add_days "1")" 1052 | #Output 1053 | 1591640826 1054 | ``` 1055 | 1056 | ### date::add_months() 1057 | 1058 | Add number of months from current day timestamp. 1059 | If number of months not specified then it defaults to 1 month. 1060 | 1061 | #### Arguments 1062 | 1063 | - **$1** (int): number of months (optional). 1064 | 1065 | #### Exit codes 1066 | 1067 | - **0**: If successful. 1068 | - **1**: If unable to generate timestamp. 1069 | 1070 | #### Output on stdout 1071 | 1072 | - timestamp. 1073 | 1074 | #### Example 1075 | 1076 | ```bash 1077 | echo "$(date::add_months "1")" 1078 | #Output 1079 | 1594146426 1080 | ``` 1081 | 1082 | ### date::add_years() 1083 | 1084 | Add number of years from current day timestamp. 1085 | If number of years not specified then it defaults to 1 year. 1086 | 1087 | #### Arguments 1088 | 1089 | - **$1** (int): number of years (optional). 1090 | 1091 | #### Exit codes 1092 | 1093 | - **0**: If successful. 1094 | - **1**: If unable to generate timestamp. 1095 | 1096 | #### Output on stdout 1097 | 1098 | - timestamp. 1099 | 1100 | #### Example 1101 | 1102 | ```bash 1103 | echo "$(date::add_years "1")" 1104 | #Output 1105 | 1623090426 1106 | ``` 1107 | 1108 | ### date::add_weeks() 1109 | 1110 | Add number of weeks from current day timestamp. 1111 | If number of weeks not specified then it defaults to 1 year. 1112 | 1113 | #### Arguments 1114 | 1115 | - **$1** (int): number of weeks (optional). 1116 | 1117 | #### Exit codes 1118 | 1119 | - **0**: If successful. 1120 | - **1**: If unable to generate timestamp. 1121 | 1122 | #### Output on stdout 1123 | 1124 | - timestamp. 1125 | 1126 | #### Example 1127 | 1128 | ```bash 1129 | echo "$(date::add_weeks "1")" 1130 | #Output 1131 | 1592159226 1132 | ``` 1133 | 1134 | ### date::add_hours() 1135 | 1136 | Add number of hours from current day timestamp. 1137 | If number of hours not specified then it defaults to 1 hour. 1138 | 1139 | #### Arguments 1140 | 1141 | - **$1** (int): number of hours (optional). 1142 | 1143 | #### Exit codes 1144 | 1145 | - **0**: If successful. 1146 | - **1**: If unable to generate timestamp. 1147 | 1148 | #### Output on stdout 1149 | 1150 | - timestamp. 1151 | 1152 | #### Example 1153 | 1154 | ```bash 1155 | echo "$(date::add_hours "1")" 1156 | #Output 1157 | 1591558026 1158 | ``` 1159 | 1160 | ### date::add_minutes() 1161 | 1162 | Add number of minutes from current day timestamp. 1163 | If number of minutes not specified then it defaults to 1 minute. 1164 | 1165 | #### Arguments 1166 | 1167 | - **$2** (int): number of minutes (optional). 1168 | 1169 | #### Exit codes 1170 | 1171 | - **0**: If successful. 1172 | - **1**: If unable to generate timestamp. 1173 | 1174 | #### Output on stdout 1175 | 1176 | - timestamp. 1177 | 1178 | #### Example 1179 | 1180 | ```bash 1181 | echo "$(date::add_minutes "1")" 1182 | #Output 1183 | 1591554486 1184 | ``` 1185 | 1186 | ### date::add_seconds() 1187 | 1188 | Add number of seconds from current day timestamp. 1189 | If number of seconds not specified then it defaults to 1 second. 1190 | 1191 | #### Arguments 1192 | 1193 | - **$2** (int): number of seconds (optional). 1194 | 1195 | #### Exit codes 1196 | 1197 | - **0**: If successful. 1198 | - **1**: If unable to generate timestamp. 1199 | 1200 | #### Output on stdout 1201 | 1202 | - timestamp. 1203 | 1204 | #### Example 1205 | 1206 | ```bash 1207 | echo "$(date::add_seconds "1")" 1208 | #Output 1209 | 1591554427 1210 | ``` 1211 | 1212 | ### date::sub_days_from() 1213 | 1214 | Subtract number of days from specified timestamp. 1215 | If number of days not specified then it defaults to 1 day. 1216 | 1217 | #### Arguments 1218 | 1219 | - **$1** (int): unix timestamp. 1220 | - **$2** (int): number of days (optional). 1221 | 1222 | #### Exit codes 1223 | 1224 | - **0**: If successful. 1225 | - **1**: If unable to generate timestamp. 1226 | - **2**: Function missing arguments. 1227 | 1228 | #### Output on stdout 1229 | 1230 | - timestamp. 1231 | 1232 | #### Example 1233 | 1234 | ```bash 1235 | echo "$(date::sub_days_from "1594143480")" 1236 | #Output 1237 | 1594057080 1238 | ``` 1239 | 1240 | ### date::sub_months_from() 1241 | 1242 | Subtract number of months from specified timestamp. 1243 | If number of months not specified then it defaults to 1 month. 1244 | 1245 | #### Arguments 1246 | 1247 | - **$1** (int): unix timestamp. 1248 | - **$2** (int): number of months (optional). 1249 | 1250 | #### Exit codes 1251 | 1252 | - **0**: If successful. 1253 | - **1**: If unable to generate timestamp. 1254 | - **2**: Function missing arguments. 1255 | 1256 | #### Output on stdout 1257 | 1258 | - timestamp. 1259 | 1260 | #### Example 1261 | 1262 | ```bash 1263 | echo "$(date::sub_months_from "1594143480")" 1264 | #Output 1265 | 1591551480 1266 | ``` 1267 | 1268 | ### date::sub_years_from() 1269 | 1270 | Subtract number of years from specified timestamp. 1271 | If number of years not specified then it defaults to 1 year. 1272 | 1273 | #### Arguments 1274 | 1275 | - **$1** (int): unix timestamp. 1276 | - **$2** (int): number of years (optional). 1277 | 1278 | #### Exit codes 1279 | 1280 | - **0**: If successful. 1281 | - **1**: If unable to generate timestamp. 1282 | - **2**: Function missing arguments. 1283 | 1284 | #### Output on stdout 1285 | 1286 | - timestamp. 1287 | 1288 | #### Example 1289 | 1290 | ```bash 1291 | echo "$(date::sub_years_from "1594143480")" 1292 | #Output 1293 | 1562521080 1294 | ``` 1295 | 1296 | ### date::sub_weeks_from() 1297 | 1298 | Subtract number of weeks from specified timestamp. 1299 | If number of weeks not specified then it defaults to 1 week. 1300 | 1301 | #### Arguments 1302 | 1303 | - **$1** (int): unix timestamp. 1304 | - **$2** (int): number of weeks (optional). 1305 | 1306 | #### Exit codes 1307 | 1308 | - **0**: If successful. 1309 | - **1**: If unable to generate timestamp. 1310 | - **2**: Function missing arguments. 1311 | 1312 | #### Output on stdout 1313 | 1314 | - timestamp. 1315 | 1316 | #### Example 1317 | 1318 | ```bash 1319 | echo "$(date::sub_weeks_from "1594143480")" 1320 | #Output 1321 | 1593538680 1322 | ``` 1323 | 1324 | ### date::sub_hours_from() 1325 | 1326 | Subtract number of hours from specified timestamp. 1327 | If number of hours not specified then it defaults to 1 hour. 1328 | 1329 | #### Arguments 1330 | 1331 | - **$1** (int): unix timestamp. 1332 | - **$2** (int): number of hours (optional). 1333 | 1334 | #### Exit codes 1335 | 1336 | - **0**: If successful. 1337 | - **1**: If unable to generate timestamp. 1338 | - **2**: Function missing arguments. 1339 | 1340 | #### Output on stdout 1341 | 1342 | - timestamp. 1343 | 1344 | #### Example 1345 | 1346 | ```bash 1347 | echo "$(date::sub_hours_from "1594143480")" 1348 | #Output 1349 | 1594139880 1350 | ``` 1351 | 1352 | ### date::sub_minutes_from() 1353 | 1354 | Subtract number of minutes from specified timestamp. 1355 | If number of minutes not specified then it defaults to 1 minute. 1356 | 1357 | #### Arguments 1358 | 1359 | - **$1** (int): unix timestamp. 1360 | - **$2** (int): number of minutes (optional). 1361 | 1362 | #### Exit codes 1363 | 1364 | - **0**: If successful. 1365 | - **1**: If unable to generate timestamp. 1366 | - **2**: Function missing arguments. 1367 | 1368 | #### Output on stdout 1369 | 1370 | - timestamp. 1371 | 1372 | #### Example 1373 | 1374 | ```bash 1375 | echo "$(date::sub_minutes_from "1594143480")" 1376 | #Output 1377 | 1594143420 1378 | ``` 1379 | 1380 | ### date::sub_seconds_from() 1381 | 1382 | Subtract number of seconds from specified timestamp. 1383 | If number of seconds not specified then it defaults to 1 second. 1384 | 1385 | #### Arguments 1386 | 1387 | - **$1** (int): unix timestamp. 1388 | - **$2** (int): number of seconds (optional). 1389 | 1390 | #### Exit codes 1391 | 1392 | - **0**: If successful. 1393 | - **1**: If unable to generate timestamp. 1394 | - **2**: Function missing arguments. 1395 | 1396 | #### Output on stdout 1397 | 1398 | - timestamp. 1399 | 1400 | #### Example 1401 | 1402 | ```bash 1403 | echo "$(date::sub_seconds_from "1594143480")" 1404 | #Output 1405 | 1594143479 1406 | ``` 1407 | 1408 | ### date::sub_days() 1409 | 1410 | Subtract number of days from current day timestamp. 1411 | If number of days not specified then it defaults to 1 day. 1412 | 1413 | #### Arguments 1414 | 1415 | - **$1** (int): number of days (optional). 1416 | 1417 | #### Exit codes 1418 | 1419 | - **0**: If successful. 1420 | - **1**: If unable to generate timestamp. 1421 | 1422 | #### Output on stdout 1423 | 1424 | - timestamp. 1425 | 1426 | #### Example 1427 | 1428 | ```bash 1429 | echo "$(date::sub_days "1")" 1430 | #Output 1431 | 1588876026 1432 | ``` 1433 | 1434 | ### date::sub_months() 1435 | 1436 | Subtract number of months from current day timestamp. 1437 | If number of months not specified then it defaults to 1 month. 1438 | 1439 | #### Arguments 1440 | 1441 | - **$1** (int): number of months (optional). 1442 | 1443 | #### Exit codes 1444 | 1445 | - **0**: If successful. 1446 | - **1**: If unable to generate timestamp. 1447 | 1448 | #### Output on stdout 1449 | 1450 | - timestamp. 1451 | 1452 | #### Example 1453 | 1454 | ```bash 1455 | echo "$(date::sub_months "1")" 1456 | #Output 1457 | 1559932026 1458 | ``` 1459 | 1460 | ### date::sub_years() 1461 | 1462 | Subtract number of years from current day timestamp. 1463 | If number of years not specified then it defaults to 1 year. 1464 | 1465 | #### Arguments 1466 | 1467 | - **$1** (int): number of years (optional). 1468 | 1469 | #### Exit codes 1470 | 1471 | - **0**: If successful. 1472 | - **1**: If unable to generate timestamp. 1473 | 1474 | #### Output on stdout 1475 | 1476 | - timestamp. 1477 | 1478 | #### Example 1479 | 1480 | ```bash 1481 | echo "$(date::sub_years "1")" 1482 | #Output 1483 | 1591468026 1484 | ``` 1485 | 1486 | ### date::sub_weeks() 1487 | 1488 | Subtract number of weeks from current day timestamp. 1489 | If number of weeks not specified then it defaults to 1 week. 1490 | 1491 | #### Arguments 1492 | 1493 | - **$1** (int): number of weeks (optional). 1494 | 1495 | #### Exit codes 1496 | 1497 | - **0**: If successful. 1498 | - **1**: If unable to generate timestamp. 1499 | 1500 | #### Output on stdout 1501 | 1502 | - timestamp. 1503 | 1504 | #### Example 1505 | 1506 | ```bash 1507 | echo "$(date::sub_weeks "1")" 1508 | #Output 1509 | 1590949626 1510 | ``` 1511 | 1512 | ### date::sub_hours() 1513 | 1514 | Subtract number of hours from current day timestamp. 1515 | If number of hours not specified then it defaults to 1 hour. 1516 | 1517 | #### Arguments 1518 | 1519 | - **$1** (int): number of hours (optional). 1520 | 1521 | #### Exit codes 1522 | 1523 | - **0**: If successful. 1524 | - **1**: If unable to generate timestamp. 1525 | 1526 | #### Output on stdout 1527 | 1528 | - timestamp. 1529 | 1530 | #### Example 1531 | 1532 | ```bash 1533 | echo "$(date::sub_hours "1")" 1534 | #Output 1535 | 1591550826 1536 | ``` 1537 | 1538 | ### date::sub_minutes() 1539 | 1540 | Subtract number of minutes from current day timestamp. 1541 | If number of minutes not specified then it defaults to 1 minute. 1542 | 1543 | #### Arguments 1544 | 1545 | - **$1** (int): number of minutes (optional). 1546 | 1547 | #### Exit codes 1548 | 1549 | - **0**: If successful. 1550 | - **1**: If unable to generate timestamp. 1551 | 1552 | #### Output on stdout 1553 | 1554 | - timestamp. 1555 | 1556 | #### Example 1557 | 1558 | ```bash 1559 | echo "$(date::sub_minutes "1")" 1560 | #Output 1561 | 1591554366 1562 | ``` 1563 | 1564 | ### date::sub_seconds() 1565 | 1566 | Subtract number of seconds from current day timestamp. 1567 | If number of seconds not specified then it defaults to 1 second. 1568 | 1569 | #### Arguments 1570 | 1571 | - **$1** (int): number of seconds (optional). 1572 | 1573 | #### Exit codes 1574 | 1575 | - **0**: If successful. 1576 | - **1**: If unable to generate timestamp. 1577 | 1578 | #### Output on stdout 1579 | 1580 | - timestamp. 1581 | 1582 | #### Example 1583 | 1584 | ```bash 1585 | echo "$(date::sub_seconds "1")" 1586 | #Output 1587 | 1591554425 1588 | ``` 1589 | 1590 | ### date::format() 1591 | 1592 | Format unix timestamp to human readable format. 1593 | If format string is not specified then it defaults to "yyyy-mm-dd hh:mm:ss" format. 1594 | 1595 | #### Arguments 1596 | 1597 | - **$1** (int): unix timestamp. 1598 | - **$2** (string): format control characters based on `date` command (optional). 1599 | 1600 | #### Exit codes 1601 | 1602 | - **0**: If successful. 1603 | - **1**: If unable to generate time string. 1604 | - **2**: Function missing arguments. 1605 | 1606 | #### Output on stdout 1607 | 1608 | - formatted time string. 1609 | 1610 | #### Example 1611 | 1612 | ```bash 1613 | echo echo "$(date::format "1594143480")" 1614 | #Output 1615 | 2020-07-07 18:38:00 1616 | ``` 1617 | 1618 | ## Debug 1619 | 1620 | Functions to facilitate debugging scripts. 1621 | 1622 | ### debug::print_array() 1623 | 1624 | Prints the content of array as key value pair for easier debugging. 1625 | Pass the variable name of the array instead of value of the variable. 1626 | 1627 | #### Arguments 1628 | 1629 | - **$1** (string): variable name of the array. 1630 | 1631 | #### Output on stdout 1632 | 1633 | - Formatted key value of array. 1634 | 1635 | #### Example 1636 | 1637 | ```bash 1638 | array=(foo bar baz) 1639 | printf "Array\n" 1640 | printarr "array" 1641 | declare -A assoc_array 1642 | assoc_array=([foo]=bar [baz]=foobar) 1643 | printf "Assoc Array\n" 1644 | printarr "assoc_array" 1645 | #Output 1646 | Array 1647 | 0 = foo 1648 | 1 = bar 1649 | 2 = baz 1650 | Assoc Array 1651 | baz = foobar 1652 | foo = bar 1653 | ``` 1654 | 1655 | ### debug::print_ansi() 1656 | 1657 | Function to print ansi escape sequence as is. 1658 | This function helps debug ansi escape sequence in text by displaying the escape codes. 1659 | 1660 | #### Arguments 1661 | 1662 | - **$1** (string): input with ansi escape sequence. 1663 | 1664 | #### Output on stdout 1665 | 1666 | - Ansi escape sequence printed in output as is. 1667 | 1668 | #### Example 1669 | 1670 | ```bash 1671 | txt="$(tput bold)$(tput setaf 9)This is bold red text$(tput sgr0).$(tput setaf 10)This is green text$(tput sgr0)" 1672 | debug::print_ansi "$txt" 1673 | #Output 1674 | \e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text\e(B\e[m 1675 | ``` 1676 | 1677 | ## File 1678 | 1679 | Functions for handling files. 1680 | 1681 | ### file::make_temp_file() 1682 | 1683 | Create temporary file. 1684 | Function creates temporary file with random name. The temporary file will be deleted when script finishes. 1685 | 1686 | *Function has no arguments.* 1687 | 1688 | #### Exit codes 1689 | 1690 | - **0**: If successful. 1691 | - **1**: If failed to create temp file. 1692 | 1693 | #### Output on stdout 1694 | 1695 | - file name of temporary file created. 1696 | 1697 | #### Example 1698 | 1699 | ```bash 1700 | echo "$(file::make_temp_file)" 1701 | #Output 1702 | tmp.vgftzy 1703 | ``` 1704 | 1705 | ### file::make_temp_dir() 1706 | 1707 | Create temporary directory. 1708 | Function creates temporary directory with random name. The temporary directory will be deleted when script finishes. 1709 | 1710 | #### Arguments 1711 | 1712 | - **$1** (string): Temporary directory prefix 1713 | - $2 string Flag to auto remove directory on exit trap (true) 1714 | 1715 | #### Exit codes 1716 | 1717 | - **0**: If successful. 1718 | - **1**: If failed to create temp directory. 1719 | - **2**: Missing arguments. 1720 | 1721 | #### Output on stdout 1722 | 1723 | - directory name of temporary directory created. 1724 | 1725 | #### Example 1726 | 1727 | ```bash 1728 | echo "$(utility::make_temp_dir)" 1729 | #Output 1730 | tmp.rtfsxy 1731 | ``` 1732 | 1733 | ### file::name() 1734 | 1735 | Get only the filename from string path. 1736 | 1737 | #### Arguments 1738 | 1739 | - **$1** (string): path. 1740 | 1741 | #### Exit codes 1742 | 1743 | - **0**: If successful. 1744 | - **2**: Function missing arguments. 1745 | 1746 | #### Output on stdout 1747 | 1748 | - name of the file with extension. 1749 | 1750 | #### Example 1751 | 1752 | ```bash 1753 | echo "$(file::name "/path/to/test.md")" 1754 | #Output 1755 | test.md 1756 | ``` 1757 | 1758 | ### file::basename() 1759 | 1760 | Get the basename of file from file name. 1761 | 1762 | #### Arguments 1763 | 1764 | - **$1** (string): path. 1765 | 1766 | #### Exit codes 1767 | 1768 | - **0**: If successful. 1769 | - **2**: Function missing arguments. 1770 | 1771 | #### Output on stdout 1772 | 1773 | - basename of the file. 1774 | 1775 | #### Example 1776 | 1777 | ```bash 1778 | echo "$(file::basename "/path/to/test.md")" 1779 | #Output 1780 | test 1781 | ``` 1782 | 1783 | ### file::extension() 1784 | 1785 | Get the extension of file from file name. 1786 | 1787 | #### Arguments 1788 | 1789 | - **$1** (string): path. 1790 | 1791 | #### Exit codes 1792 | 1793 | - **0**: If successful. 1794 | - **1**: If no extension is found in the filename. 1795 | - **2**: Function missing arguments. 1796 | 1797 | #### Output on stdout 1798 | 1799 | - extension of the file. 1800 | 1801 | #### Example 1802 | 1803 | ```bash 1804 | echo "$(file::extension "/path/to/test.md")" 1805 | #Output 1806 | md 1807 | ``` 1808 | 1809 | ### file::dirname() 1810 | 1811 | Get directory name from file path. 1812 | 1813 | #### Arguments 1814 | 1815 | - **$1** (string): path. 1816 | 1817 | #### Exit codes 1818 | 1819 | - **0**: If successful. 1820 | - **2**: Function missing arguments. 1821 | 1822 | #### Output on stdout 1823 | 1824 | - directory path. 1825 | 1826 | #### Example 1827 | 1828 | ```bash 1829 | echo "$(file::dirname "/path/to/test.md")" 1830 | #Output 1831 | /path/to 1832 | ``` 1833 | 1834 | ### file::full_path() 1835 | 1836 | Get absolute path of file or directory. 1837 | 1838 | #### Arguments 1839 | 1840 | - **$1** (string): relative or absolute path to file/direcotry. 1841 | 1842 | #### Exit codes 1843 | 1844 | - **0**: If successful. 1845 | - **1**: If file/directory does not exist. 1846 | - **2**: Function missing arguments. 1847 | 1848 | #### Output on stdout 1849 | 1850 | - Absolute path to file/directory. 1851 | 1852 | #### Example 1853 | 1854 | ```bash 1855 | file::full_path "../path/to/file.md" 1856 | #Output 1857 | /home/labbots/docs/path/to/file.md 1858 | ``` 1859 | 1860 | ### file::mime_type() 1861 | 1862 | Get mime type of provided input. 1863 | 1864 | #### Arguments 1865 | 1866 | - **$1** (string): relative or absolute path to file/directory. 1867 | 1868 | #### Exit codes 1869 | 1870 | - **0**: If successful. 1871 | - **1**: If file/directory does not exist. 1872 | - **2**: Function missing arguments. 1873 | - **3**: If file or mimetype command not found in system. 1874 | 1875 | #### Output on stdout 1876 | 1877 | - mime type of file/directory. 1878 | 1879 | #### Example 1880 | 1881 | ```bash 1882 | file::mime_type "../src/file.sh" 1883 | #Output 1884 | application/x-shellscript 1885 | ``` 1886 | 1887 | ### file::contains_text() 1888 | 1889 | Search if a given pattern is found in file. 1890 | 1891 | #### Arguments 1892 | 1893 | - **$1** (string): relative or absolute path to file/directory. 1894 | - **$2** (string): search key or regular expression. 1895 | 1896 | #### Exit codes 1897 | 1898 | - **0**: If given search parameter is found in file. 1899 | - **1**: If search paramter not found in file. 1900 | - **2**: Function missing arguments. 1901 | 1902 | #### Example 1903 | 1904 | ```bash 1905 | file::contains_text "./file.sh" "^[ @[:alpha:]]*" 1906 | file::contains_text "./file.sh" "@file" 1907 | #Output 1908 | 0 1909 | ``` 1910 | 1911 | ## Format 1912 | 1913 | Functions to format provided input. 1914 | 1915 | ### format::human_readable_seconds() 1916 | 1917 | Format seconds to human readable format. 1918 | 1919 | #### Arguments 1920 | 1921 | - **$1** (int): number of seconds. 1922 | 1923 | #### Exit codes 1924 | 1925 | - **0**: If successful. 1926 | - **2**: Function missing arguments. 1927 | 1928 | #### Output on stdout 1929 | 1930 | - formatted time string. 1931 | 1932 | #### Example 1933 | 1934 | ```bash 1935 | echo "$(format::human_readable_seconds "356786")" 1936 | #Output 1937 | 4 days 3 hours 6 minute(s) and 26 seconds 1938 | ``` 1939 | 1940 | ### format::bytes_to_human() 1941 | 1942 | Format bytes to human readable format. 1943 | 1944 | #### Arguments 1945 | 1946 | - **$1** (int): size in bytes. 1947 | 1948 | #### Exit codes 1949 | 1950 | - **0**: If successful. 1951 | - **2**: Function missing arguments. 1952 | 1953 | #### Output on stdout 1954 | 1955 | - formatted file size string. 1956 | 1957 | #### Example 1958 | 1959 | ```bash 1960 | echo "$(format::bytes_to_human "2250")" 1961 | #Output 1962 | 2.19 KB 1963 | ``` 1964 | 1965 | ### format::strip_ansi() 1966 | 1967 | Remove Ansi escape sequences from given text. 1968 | 1969 | #### Arguments 1970 | 1971 | - **$1** (string): Input text to be ansi stripped. 1972 | 1973 | #### Exit codes 1974 | 1975 | - **0**: If successful. 1976 | 1977 | #### Output on stdout 1978 | 1979 | - Ansi stripped text. 1980 | 1981 | #### Example 1982 | 1983 | ```bash 1984 | format::strip_ansi "\e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text.\e(B\e[m" 1985 | #Output 1986 | This is bold red text.This is green text. 1987 | ``` 1988 | 1989 | ### format::text_center() 1990 | 1991 | Prints the given text to centre of terminal. 1992 | 1993 | #### Arguments 1994 | 1995 | - **$1** (string): Text to be printed. 1996 | - **$2** (string): Filler symbol to be added to prefix and suffix of the text (optional). Defaults to space as filler. 1997 | 1998 | #### Exit codes 1999 | 2000 | - **0**: If successful. 2001 | - **2**: Function missing arguments. 2002 | 2003 | #### Output on stdout 2004 | 2005 | - formatted text. 2006 | 2007 | #### Example 2008 | 2009 | ```bash 2010 | format::text_center "This text is in centre of the terminal." "-" 2011 | ``` 2012 | 2013 | ### format::report() 2014 | 2015 | Format String to print beautiful report. 2016 | 2017 | #### Arguments 2018 | 2019 | - **$1** (string): Text to be printed on the left. 2020 | - **$2** (string): Text to be printed within the square brackets. 2021 | 2022 | #### Exit codes 2023 | 2024 | - **0**: If successful. 2025 | - **2**: Function missing arguments. 2026 | 2027 | #### Output on stdout 2028 | 2029 | - formatted text. 2030 | 2031 | #### Example 2032 | 2033 | ```bash 2034 | format::report "Initialising mission state" "Success" 2035 | #Output 2036 | Initialising mission state ....................................................................[ Success ] 2037 | ``` 2038 | 2039 | ### format::trim_text_to_term() 2040 | 2041 | Trim given text to width of the terminal window. 2042 | 2043 | #### Arguments 2044 | 2045 | - **$1** (string): Text of first sentence. 2046 | - **$2** (string): Text of second sentence (optional). 2047 | 2048 | #### Exit codes 2049 | 2050 | - **0**: If successful. 2051 | - **2**: Function missing arguments. 2052 | 2053 | #### Output on stdout 2054 | 2055 | - trimmed text. 2056 | 2057 | #### Example 2058 | 2059 | ```bash 2060 | 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." 2061 | #Output 2062 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..This is part of second sentence. 2063 | ``` 2064 | 2065 | ## Interaction 2066 | 2067 | Functions to enable interaction with the user. 2068 | 2069 | ### interaction::prompt_yes_no() 2070 | 2071 | Prompt yes or no question to the user. 2072 | 2073 | #### Arguments 2074 | 2075 | - **$1** (string): The question to be prompted to the user. 2076 | - **$2** (string): default answer \[yes/no\] (optional). 2077 | 2078 | #### Exit codes 2079 | 2080 | - **0**: If user responds with yes. 2081 | - **1**: If user responds with no. 2082 | - **2**: Function missing arguments. 2083 | 2084 | #### Example 2085 | 2086 | ```bash 2087 | interaction::prompt_yes_no "Are you sure to proceed" "yes" 2088 | #Output 2089 | Are you sure to proceed (y/n)? [y] 2090 | ``` 2091 | 2092 | ### interaction::prompt_response() 2093 | 2094 | Prompt question to the user. 2095 | 2096 | #### Arguments 2097 | 2098 | - **$1** (string): The question to be prompted to the user. 2099 | - **$2** (string): default answer (optional). 2100 | 2101 | #### Exit codes 2102 | 2103 | - **0**: If user responds with answer. 2104 | - **2**: Function missing arguments. 2105 | 2106 | #### Output on stdout 2107 | 2108 | - User entered answer to the question. 2109 | 2110 | #### Example 2111 | 2112 | ```bash 2113 | interaction::prompt_response "Choose directory to install" "/home/path" 2114 | #Output 2115 | Choose directory to install? [/home/path] 2116 | ``` 2117 | 2118 | ## Json 2119 | 2120 | Simple json manipulation. These functions does not completely replace `jq` in any way. 2121 | 2122 | ### json::get_value() 2123 | 2124 | Extract value from json based on key and position. 2125 | Input to the function can be a pipe output, here-string or file. 2126 | 2127 | #### Arguments 2128 | 2129 | - **$1** (string): id of the field to fetch. 2130 | - **$2** (int): position of value to extract.Defaults to 1.(optional) 2131 | 2132 | #### Exit codes 2133 | 2134 | - **0**: If match successful. 2135 | - **2**: Function missing arguments. 2136 | 2137 | #### Output on stdout 2138 | 2139 | - string value of extracted key. 2140 | 2141 | #### Example 2142 | 2143 | ```bash 2144 | json::get_value "id" "1" < json_file 2145 | json::get_value "id" <<< "${json_var}" 2146 | echo "{\"data\":{\"id\":\"123\",\"value\":\"name string\"}}" | json::get_value "id" 2147 | ``` 2148 | 2149 | ## Miscellaneous 2150 | 2151 | Set of miscellaneous helper functions. 2152 | 2153 | ### misc::check_internet_connection() 2154 | 2155 | Check if internet connection is available. 2156 | 2157 | *Function has no arguments.* 2158 | 2159 | #### Exit codes 2160 | 2161 | - **0**: If script can connect to internet. 2162 | - **1**: If script cannot access internet. 2163 | 2164 | #### Example 2165 | 2166 | ```bash 2167 | misc::check_internet_connection 2168 | ``` 2169 | 2170 | ### misc::get_pid() 2171 | 2172 | Get list of process ids based on process name. 2173 | 2174 | #### Arguments 2175 | 2176 | - **$1** (Name): of the process to search. 2177 | 2178 | #### Exit codes 2179 | 2180 | - **0**: If match successful. 2181 | - **2**: Function missing arguments. 2182 | 2183 | #### Output on stdout 2184 | 2185 | - list of process ids. 2186 | 2187 | #### Example 2188 | 2189 | ```bash 2190 | misc::get_pid "chrome" 2191 | #Ouput 2192 | 25951 2193 | 26043 2194 | 26528 2195 | 26561 2196 | ``` 2197 | 2198 | ### misc::get_uid() 2199 | 2200 | Get user id based on username. 2201 | 2202 | #### Arguments 2203 | 2204 | - **$1** (username): to search. 2205 | 2206 | #### Exit codes 2207 | 2208 | - **0**: If match successful. 2209 | - **2**: Function missing arguments. 2210 | 2211 | #### Output on stdout 2212 | 2213 | - string uid for the username. 2214 | 2215 | #### Example 2216 | 2217 | ```bash 2218 | misc::get_uid "labbots" 2219 | #Ouput 2220 | 1000 2221 | ``` 2222 | 2223 | ### misc::generate_uuid() 2224 | 2225 | Generate random uuid. 2226 | 2227 | *Function has no arguments.* 2228 | 2229 | #### Exit codes 2230 | 2231 | - **0**: If match successful. 2232 | 2233 | #### Output on stdout 2234 | 2235 | - random generated uuid. 2236 | 2237 | #### Example 2238 | 2239 | ```bash 2240 | misc::generate_uuid 2241 | #Ouput 2242 | 65bc64d1-d355-4ffc-a9d9-dc4f3954c34c 2243 | ``` 2244 | 2245 | ## Operating System 2246 | 2247 | Functions to detect Operating system and version. 2248 | 2249 | ### os::detect_os() 2250 | 2251 | Identify the OS the function is run on. 2252 | 2253 | *Function has no arguments.* 2254 | 2255 | #### Exit codes 2256 | 2257 | - **0**: If OS is successfully detected. 2258 | - **1**: If unable to detect OS. 2259 | 2260 | #### Output on stdout 2261 | 2262 | - Operating system name (linux, mac or windows). 2263 | 2264 | #### Example 2265 | 2266 | ```bash 2267 | os::detect_os 2268 | #Output 2269 | linux 2270 | ``` 2271 | 2272 | ### os::detect_linux_distro() 2273 | 2274 | Identify the distribution flavour of linux. 2275 | 2276 | *Function has no arguments.* 2277 | 2278 | #### Exit codes 2279 | 2280 | - **0**: If Linux distro is successfully detected. 2281 | - **1**: If unable to detect OS distro. 2282 | 2283 | #### Output on stdout 2284 | 2285 | - Linux OS distribution name (ubuntu, debian, suse, etc.,). 2286 | 2287 | #### Example 2288 | 2289 | ```bash 2290 | os::detect_linux_distro 2291 | #Output 2292 | ubuntu 2293 | ``` 2294 | 2295 | ### os::detect_linux_version() 2296 | 2297 | Identify the Linux version. 2298 | 2299 | *Function has no arguments.* 2300 | 2301 | #### Exit codes 2302 | 2303 | - **0**: If Linux version is successfully detected. 2304 | - **1**: If unable to detect Linux version. 2305 | 2306 | #### Output on stdout 2307 | 2308 | - Linux OS version number (18.04, 20.04, etc.,). 2309 | 2310 | #### Example 2311 | 2312 | ```bash 2313 | os::detect_linux_version 2314 | #Output 2315 | 20.04 2316 | ``` 2317 | 2318 | ### os::detect_mac_version() 2319 | 2320 | Identify the MacOS version. 2321 | 2322 | *Function has no arguments.* 2323 | 2324 | #### Exit codes 2325 | 2326 | - **0**: If MacOS version is successfully detected. 2327 | - **1**: If unable to detect MacOS version. 2328 | 2329 | #### Output on stdout 2330 | 2331 | - MacOS version number (10.15.6, etc.,) 2332 | 2333 | #### Example 2334 | 2335 | ```bash 2336 | os::detect_linux_version 2337 | #Output 2338 | 10.15.7 2339 | ``` 2340 | 2341 | ## String 2342 | 2343 | Functions for string operations and manipulations. 2344 | 2345 | ### string::trim() 2346 | 2347 | Strip whitespace from the beginning and end of a string. 2348 | 2349 | #### Arguments 2350 | 2351 | - **$1** (string): The string to be trimmed. 2352 | 2353 | #### Exit codes 2354 | 2355 | - **0**: If successful. 2356 | - **2**: Function missing arguments. 2357 | 2358 | #### Output on stdout 2359 | 2360 | - The trimmed string. 2361 | 2362 | #### Example 2363 | 2364 | ```bash 2365 | echo "$(string::trim " Hello World! ")" 2366 | #Output 2367 | Hello World! 2368 | ``` 2369 | 2370 | ### string::split() 2371 | 2372 | Split a string to array by a delimiter. 2373 | 2374 | #### Arguments 2375 | 2376 | - **$1** (string): The input string. 2377 | - **$2** (string): The delimiter string. 2378 | 2379 | #### Exit codes 2380 | 2381 | - **0**: If successful. 2382 | - **2**: Function missing arguments. 2383 | 2384 | #### Output on stdout 2385 | 2386 | - Returns an array of strings created by splitting the string parameter by the delimiter. 2387 | 2388 | #### Example 2389 | 2390 | ```bash 2391 | array=( $(string::split "a,b,c" ",") ) 2392 | printf "%s" "$(string::split "Hello!World" "!")" 2393 | #Output 2394 | Hello 2395 | World 2396 | ``` 2397 | 2398 | ### string::lstrip() 2399 | 2400 | Strip characters from the beginning of a string. 2401 | 2402 | #### Arguments 2403 | 2404 | - **$1** (string): The input string. 2405 | - **$2** (string): The characters you want to strip. 2406 | 2407 | #### Exit codes 2408 | 2409 | - **0**: If successful. 2410 | - **2**: Function missing arguments. 2411 | 2412 | #### Output on stdout 2413 | 2414 | - Returns the modified string. 2415 | 2416 | #### Example 2417 | 2418 | ```bash 2419 | echo "$(string::lstrip "Hello World!" "He")" 2420 | #Output 2421 | llo World! 2422 | ``` 2423 | 2424 | ### string::rstrip() 2425 | 2426 | Strip characters from the end of a string. 2427 | 2428 | #### Arguments 2429 | 2430 | - **$1** (string): The input string. 2431 | - **$2** (string): The characters you want to strip. 2432 | 2433 | #### Exit codes 2434 | 2435 | - **0**: If successful. 2436 | - **2**: Function missing arguments. 2437 | 2438 | #### Output on stdout 2439 | 2440 | - Returns the modified string. 2441 | 2442 | #### Example 2443 | 2444 | ```bash 2445 | echo "$(string::rstrip "Hello World!" "d!")" 2446 | #Output 2447 | Hello Worl 2448 | ``` 2449 | 2450 | ### string::to_lower() 2451 | 2452 | Make a string lowercase. 2453 | 2454 | #### Arguments 2455 | 2456 | - **$1** (string): The input string. 2457 | 2458 | #### Exit codes 2459 | 2460 | - **0**: If successful. 2461 | - **2**: Function missing arguments. 2462 | 2463 | #### Output on stdout 2464 | 2465 | - Returns the lowercased string. 2466 | 2467 | #### Example 2468 | 2469 | ```bash 2470 | echo "$(string::to_lower "HellO")" 2471 | #Output 2472 | hello 2473 | ``` 2474 | 2475 | ### string::to_upper() 2476 | 2477 | Make a string all uppercase. 2478 | 2479 | #### Arguments 2480 | 2481 | - **$1** (string): The input string. 2482 | 2483 | #### Exit codes 2484 | 2485 | - **0**: If successful. 2486 | - **2**: Function missing arguments. 2487 | 2488 | #### Output on stdout 2489 | 2490 | - Returns the uppercased string. 2491 | 2492 | #### Example 2493 | 2494 | ```bash 2495 | echo "$(string::to_upper "HellO")" 2496 | #Output 2497 | HELLO 2498 | ``` 2499 | 2500 | ### string::contains() 2501 | 2502 | Check whether the search string exists within the input string. 2503 | 2504 | #### Arguments 2505 | 2506 | - **$1** (string): The input string. 2507 | - **$2** (string): The search key. 2508 | 2509 | #### Exit codes 2510 | 2511 | - **0**: If match found. 2512 | - **1**: If no match found. 2513 | - **2**: Function missing arguments. 2514 | 2515 | #### Example 2516 | 2517 | ```bash 2518 | string::contains "Hello World!" "lo" 2519 | ``` 2520 | 2521 | ### string::starts_with() 2522 | 2523 | Check whether the input string starts with key string. 2524 | 2525 | #### Arguments 2526 | 2527 | - **$1** (string): The input string. 2528 | - **$2** (string): The search key. 2529 | 2530 | #### Exit codes 2531 | 2532 | - **0**: If match found. 2533 | - **1**: If no match found. 2534 | - **2**: Function missing arguments. 2535 | 2536 | #### Example 2537 | 2538 | ```bash 2539 | string::starts_with "Hello World!" "He" 2540 | ``` 2541 | 2542 | ### string::ends_with() 2543 | 2544 | Check whether the input string ends with key string. 2545 | 2546 | #### Arguments 2547 | 2548 | - **$1** (string): The input string. 2549 | - **$2** (string): The search key. 2550 | 2551 | #### Exit codes 2552 | 2553 | - **0**: If match found. 2554 | - **1**: If no match found. 2555 | - **2**: Function missing arguments. 2556 | 2557 | #### Example 2558 | 2559 | ```bash 2560 | string::ends_with "Hello World!" "d!" 2561 | ``` 2562 | 2563 | ### string::regex() 2564 | 2565 | Check whether the input string matches the given regex. 2566 | 2567 | #### Arguments 2568 | 2569 | - **$1** (string): The input string. 2570 | - **$2** (string): The search key. 2571 | 2572 | #### Exit codes 2573 | 2574 | - **0**: If match found. 2575 | - **1**: If no match found. 2576 | - **2**: Function missing arguments. 2577 | 2578 | #### Example 2579 | 2580 | ```bash 2581 | string::regex "HELLO" "^[A-Z]*$" 2582 | ``` 2583 | 2584 | ## Terminal 2585 | 2586 | Set of useful terminal functions. 2587 | 2588 | ### terminal::is_term() 2589 | 2590 | Check if script is run in terminal. 2591 | 2592 | *Function has no arguments.* 2593 | 2594 | #### Exit codes 2595 | 2596 | - **0**: If script is run on terminal. 2597 | - **1**: If script is not run on terminal. 2598 | 2599 | ### terminal::detect_profile() 2600 | 2601 | Detect profile rc file for zsh and bash of current script running user. 2602 | 2603 | *Function has no arguments.* 2604 | 2605 | #### Exit codes 2606 | 2607 | - **0**: If script is run on terminal. 2608 | - **1**: If script is not run on terminal. 2609 | 2610 | #### Output on stdout 2611 | 2612 | - path to the profile file. 2613 | 2614 | ### terminal::clear_line() 2615 | 2616 | Clear the output in terminal on the specified line number. 2617 | This function clears line only on terminal. 2618 | 2619 | #### Arguments 2620 | 2621 | - **$1** (Line): number to clear. Defaults to 1. (optional) 2622 | 2623 | #### Exit codes 2624 | 2625 | - **0**: If script is run on terminal. 2626 | 2627 | #### Output on stdout 2628 | 2629 | - clear line ansi code. 2630 | 2631 | ## Validation 2632 | 2633 | Functions to perform validation on given data. 2634 | 2635 | ### validation::email() 2636 | 2637 | Validate whether a given input is a valid email address or not. 2638 | 2639 | #### Arguments 2640 | 2641 | - **$1** (string): input email address to validate. 2642 | 2643 | #### Exit codes 2644 | 2645 | - **0**: If provided input is an email address. 2646 | - **1**: If provided input is not an email address. 2647 | - **2**: Function missing arguments. 2648 | 2649 | #### Example 2650 | 2651 | ```bash 2652 | test='test@gmail.com' 2653 | validation::email "${test}" 2654 | echo $? 2655 | #Output 2656 | 0 2657 | ``` 2658 | 2659 | ### validation::ipv4() 2660 | 2661 | Validate whether a given input is a valid IP V4 address. 2662 | 2663 | #### Arguments 2664 | 2665 | - **$1** (string): input IPv4 address. 2666 | 2667 | #### Exit codes 2668 | 2669 | - **0**: If provided input is a valid IPv4. 2670 | - **1**: If provided input is not a valid IPv4. 2671 | - **2**: Function missing arguments. 2672 | 2673 | #### Example 2674 | 2675 | ```bash 2676 | ips=' 2677 | 4.2.2.2 2678 | a.b.c.d 2679 | 192.168.1.1 2680 | 0.0.0.0 2681 | 255.255.255.255 2682 | 255.255.255.256 2683 | 192.168.0.1 2684 | 192.168.0 2685 | 1234.123.123.123 2686 | 0.192.168.1 2687 | ' 2688 | for ip in $ips; do 2689 | if validation::ipv4 $ip; then stat='good'; else stat='bad'; fi 2690 | printf "%-20s: %s\n" "$ip" "$stat" 2691 | done 2692 | #Output 2693 | 4.2.2.2 : good 2694 | a.b.c.d : bad 2695 | 192.168.1.1 : good 2696 | 0.0.0.0 : good 2697 | 255.255.255.255 : good 2698 | 255.255.255.256 : bad 2699 | 192.168.0.1 : good 2700 | 192.168.0 : bad 2701 | 1234.123.123.123 : bad 2702 | 0.192.168.1 : good 2703 | ``` 2704 | 2705 | ### validation::ipv6() 2706 | 2707 | Validate whether a given input is a valid IP V6 address. 2708 | 2709 | #### Arguments 2710 | 2711 | - **$1** (string): input IPv6 address. 2712 | 2713 | #### Exit codes 2714 | 2715 | - **0**: If provided input is a valid IPv6. 2716 | - **1**: If provided input is not a valid IPv6. 2717 | - **2**: Function missing arguments. 2718 | 2719 | #### Example 2720 | 2721 | ```bash 2722 | ips=' 2723 | 2001:db8:85a3:8d3:1319:8a2e:370:7348 2724 | fe80::1ff:fe23:4567:890a 2725 | fe80::1ff:fe23:4567:890a%eth2 2726 | 2001:0db8:85a3:0000:0000:8a2e:0370:7334:foo:bar 2727 | fezy::1ff:fe23:4567:890a 2728 | :: 2729 | 2001:db8:: 2730 | ' 2731 | for ip in $ips; do 2732 | if validation::ipv6 $ip; then stat='good'; else stat='bad'; fi 2733 | printf "%-50s= %s\n" "$ip" "$stat" 2734 | done 2735 | #Output 2736 | 2001:db8:85a3:8d3:1319:8a2e:370:7348 = good 2737 | fe80::1ff:fe23:4567:890a = good 2738 | fe80::1ff:fe23:4567:890a%eth2 = good 2739 | 2001:0db8:85a3:0000:0000:8a2e:0370:7334:foo:bar = bad 2740 | fezy::1ff:fe23:4567:890a = bad 2741 | :: = good 2742 | 2001:db8:: = good 2743 | ``` 2744 | 2745 | ### validation::alpha() 2746 | 2747 | Validate if given variable is entirely alphabetic characters. 2748 | 2749 | #### Arguments 2750 | 2751 | - **$1** (string): Value of variable to validate. 2752 | 2753 | #### Exit codes 2754 | 2755 | - **0**: If input is only alpha characters. 2756 | - **1**: If input contains any non alpha characters. 2757 | - **2**: Function missing arguments. 2758 | 2759 | #### Example 2760 | 2761 | ```bash 2762 | test='abcABC' 2763 | validation::alpha "${test}" 2764 | echo $? 2765 | #Output 2766 | 0 2767 | ``` 2768 | 2769 | ### validation::alpha_num() 2770 | 2771 | Check if given variable contains only alpha-numeric characters. 2772 | 2773 | #### Arguments 2774 | 2775 | - **$1** (string): Value of variable to validate. 2776 | 2777 | #### Exit codes 2778 | 2779 | - **0**: If input is an alpha-numeric. 2780 | - **1**: If input is not an alpha-numeric. 2781 | - **2**: Function missing arguments. 2782 | 2783 | #### Example 2784 | 2785 | ```bash 2786 | test='abc123' 2787 | validation::alpha_num "${test}" 2788 | echo $? 2789 | #Output 2790 | 0 2791 | ``` 2792 | 2793 | ### validation::alpha_dash() 2794 | 2795 | Validate if given variable contains only alpha-numeric characters, as well as dashes and underscores. 2796 | 2797 | #### Arguments 2798 | 2799 | - **$1** (string): Value of variable to validate. 2800 | 2801 | #### Exit codes 2802 | 2803 | - **0**: If input is valid. 2804 | - **1**: If input the input is not valid. 2805 | - **2**: Function missing arguments. 2806 | 2807 | #### Example 2808 | 2809 | ```bash 2810 | test='abc-ABC_cD' 2811 | validation::alpha_dash "${test}" 2812 | echo $? 2813 | #Output 2814 | 0 2815 | ``` 2816 | 2817 | ### validation::version_comparison() 2818 | 2819 | Compares version numbers and provides return based on whether the value in equal, less than or greater. 2820 | 2821 | #### Arguments 2822 | 2823 | - **$1** (string): Version number to check (eg: 1.0.1) 2824 | 2825 | #### Exit codes 2826 | 2827 | - **0**: version number is equal. 2828 | - **1**: $1 version number is greater than $2. 2829 | - **2**: $1 version number is less than $2. 2830 | - **3**: Function is missing required arguments. 2831 | - **4**: Provided input argument is in invalid format. 2832 | 2833 | #### Example 2834 | 2835 | ```bash 2836 | test='abc-ABC_cD' 2837 | validation::version_comparison "12.0.1" "12.0.1" 2838 | echo $? 2839 | #Output 2840 | 0 2841 | ``` 2842 | 2843 | ## Variable 2844 | 2845 | Functions for handling variables. 2846 | 2847 | ### variable::is_array() 2848 | 2849 | Check if given variable is array. 2850 | Pass the variable name instead of value of the variable. 2851 | 2852 | #### Arguments 2853 | 2854 | - **$1** (string): name of the variable to check. 2855 | 2856 | #### Exit codes 2857 | 2858 | - **0**: If input is array. 2859 | - **1**: If input is not an array. 2860 | 2861 | #### Example 2862 | 2863 | ```bash 2864 | arr=("a" "b" "c") 2865 | variable::is_array "arr" 2866 | #Output 2867 | 0 2868 | ``` 2869 | 2870 | ### variable::is_numeric() 2871 | 2872 | Check if given variable is a number. 2873 | 2874 | #### Arguments 2875 | 2876 | - **$1** (mixed): Value of variable to check. 2877 | 2878 | #### Exit codes 2879 | 2880 | - **0**: If input is number. 2881 | - **1**: If input is not a number. 2882 | 2883 | #### Example 2884 | 2885 | ```bash 2886 | variable::is_numeric "1234" 2887 | #Output 2888 | 0 2889 | ``` 2890 | 2891 | ### variable::is_int() 2892 | 2893 | Check if given variable is an integer. 2894 | 2895 | #### Arguments 2896 | 2897 | - **$1** (mixed): Value of variable to check. 2898 | 2899 | #### Exit codes 2900 | 2901 | - **0**: If input is an integer. 2902 | - **1**: If input is not an integer. 2903 | 2904 | #### Example 2905 | 2906 | ```bash 2907 | variable::is_int "+1234" 2908 | #Output 2909 | 0 2910 | ``` 2911 | 2912 | ### variable::is_float() 2913 | 2914 | Check if given variable is a float. 2915 | 2916 | #### Arguments 2917 | 2918 | - **$1** (mixed): Value of variable to check. 2919 | 2920 | #### Exit codes 2921 | 2922 | - **0**: If input is a float. 2923 | - **1**: If input is not a float. 2924 | 2925 | #### Example 2926 | 2927 | ```bash 2928 | variable::is_float "+1234.0" 2929 | #Output 2930 | 0 2931 | ``` 2932 | 2933 | ### variable::is_bool() 2934 | 2935 | Check if given variable is a boolean. 2936 | 2937 | #### Arguments 2938 | 2939 | - **$1** (mixed): Value of variable to check. 2940 | 2941 | #### Exit codes 2942 | 2943 | - **0**: If input is a boolean. 2944 | - **1**: If input is not a boolean. 2945 | 2946 | #### Example 2947 | 2948 | ```bash 2949 | variable::is_bool "true" 2950 | #Output 2951 | 0 2952 | ``` 2953 | 2954 | ### variable::is_true() 2955 | 2956 | Check if given variable is a true. 2957 | 2958 | #### Arguments 2959 | 2960 | - **$1** (mixed): Value of variable to check. 2961 | 2962 | #### Exit codes 2963 | 2964 | - **0**: If input is true. 2965 | - **1**: If input is not true. 2966 | 2967 | #### Example 2968 | 2969 | ```bash 2970 | variable::is_true "true" 2971 | #Output 2972 | 0 2973 | ``` 2974 | 2975 | ### variable::is_false() 2976 | 2977 | Check if given variable is false. 2978 | 2979 | #### Arguments 2980 | 2981 | - **$1** (mixed): Value of variable to check. 2982 | 2983 | #### Exit codes 2984 | 2985 | - **0**: If input is false. 2986 | - **1**: If input is not false. 2987 | 2988 | #### Example 2989 | 2990 | ```bash 2991 | variable::is_false "false" 2992 | #Output 2993 | 0 2994 | ``` 2995 | 2996 | ### variable::is_empty_or_null() 2997 | 2998 | Check if given variable is empty or null. 2999 | 3000 | #### Arguments 3001 | 3002 | - **$1** (mixed): Value of variable to check. 3003 | 3004 | #### Exit codes 3005 | 3006 | - **0**: If input is empty or null. 3007 | - **1**: If input is not empty or null. 3008 | 3009 | #### Example 3010 | 3011 | ```bash 3012 | test='' 3013 | variable::is_empty_or_null $test 3014 | #Output 3015 | 0 3016 | ``` 3017 | 3018 | 3019 | 3020 | ## Inspired By 3021 | 3022 | - [Bash Bible](https://github.com/dylanaraps/pure-bash-bible) - A collection of pure bash alternatives to external processes. 3023 | 3024 | ## License 3025 | 3026 | [MIT](https://github.com/labbots/google-drive-upload/blob/master/LICENSE) 3027 | -------------------------------------------------------------------------------- /bash_utility.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # shellcheck disable=SC1091 4 | source src/array.sh 5 | source src/string.sh 6 | source src/variable.sh 7 | source src/file.sh 8 | source src/misc.sh 9 | source src/date.sh 10 | source src/interaction.sh 11 | source src/check.sh 12 | source src/format.sh 13 | source src/collection.sh 14 | source src/json.sh 15 | source src/terminal.sh 16 | source src/validation.sh 17 | source src/debug.sh 18 | source src/os.sh 19 | 20 | 21 | -------------------------------------------------------------------------------- /bin/bashdoc.awk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk -f 2 | 3 | # Varibles 4 | # style = readme or doc 5 | # toc = true or false 6 | BEGIN { 7 | if (! style) { 8 | style = "doc" 9 | } 10 | 11 | if (! toc) { 12 | toc = 0 13 | } 14 | 15 | styles["empty", "from"] = ".*" 16 | styles["empty", "to"] = "" 17 | 18 | styles["h1", "from"] = ".*" 19 | styles["h1", "to"] = "# &" 20 | 21 | styles["h2", "from"] = ".*" 22 | styles["h2", "to"] = "## &" 23 | 24 | styles["h3", "from"] = ".*" 25 | styles["h3", "to"] = "### &" 26 | 27 | styles["h4", "from"] = ".*" 28 | styles["h4", "to"] = "#### &" 29 | 30 | styles["h5", "from"] = ".*" 31 | styles["h5", "to"] = "##### &" 32 | 33 | styles["code", "from"] = ".*" 34 | styles["code", "to"] = "```&" 35 | 36 | styles["/code", "to"] = "```" 37 | 38 | styles["argN", "from"] = "^(\\$[0-9]) (\\S+)" 39 | styles["argN", "to"] = "**\\1** (\\2):" 40 | 41 | styles["arg@", "from"] = "^\\$@ (\\S+)" 42 | styles["arg@", "to"] = "**...** (\\1):" 43 | 44 | styles["li", "from"] = ".*" 45 | styles["li", "to"] = "- &" 46 | 47 | styles["i", "from"] = ".*" 48 | styles["i", "to"] = "*&*" 49 | 50 | styles["anchor", "from"] = ".*" 51 | styles["anchor", "to"] = "[&](#&)" 52 | 53 | styles["exitcode", "from"] = "([>!]?[0-9]{1,3}) (.*)" 54 | styles["exitcode", "to"] = "**\\1**: \\2" 55 | 56 | styles["h_rule", "to"] = "---" 57 | 58 | styles["comment", "from"] = ".*" 59 | styles["comment", "to"] = "" 60 | 61 | 62 | output_format["readme", "h1"] = "h2" 63 | output_format["readme", "h2"] = "h3" 64 | output_format["readme", "h3"] = "h4" 65 | output_format["readme", "h4"] = "h5" 66 | 67 | output_format["bashdoc", "h1"] = "h1" 68 | output_format["bashdoc", "h2"] = "h2" 69 | output_format["bashdoc", "h3"] = "h3" 70 | output_format["bashdoc", "h4"] = "h4" 71 | 72 | output_format["webdoc", "h1"] = "empty" 73 | output_format["webdoc", "h2"] = "h3" 74 | output_format["webdoc", "h3"] = "h4" 75 | output_format["webdoc", "h4"] = "h5" 76 | 77 | } 78 | 79 | function render(type, text) { 80 | if((style,type) in output_format){ 81 | type = output_format[style,type] 82 | } 83 | return gensub( \ 84 | styles[type, "from"], 85 | styles[type, "to"], 86 | "g", 87 | text \ 88 | ) 89 | } 90 | 91 | function render_list(item, anchor) { 92 | return "- [" item "](#" anchor ")" 93 | } 94 | 95 | function generate_anchor(text) { 96 | # https://github.com/jch/html-pipeline/blob/master/lib/html/pipeline/toc_filter.rb#L44-L45 97 | text = tolower(text) 98 | gsub(/[^[:alnum:]_ -]/, "", text) 99 | gsub(/ /, "-", text) 100 | return text 101 | } 102 | 103 | function reset() { 104 | has_example = 0 105 | has_args = 0 106 | has_exitcode = 0 107 | has_stdout = 0 108 | 109 | content_desc = "" 110 | content_example = "" 111 | content_args = "" 112 | content_exitcode = "" 113 | content_seealso = "" 114 | content_stdout = "" 115 | } 116 | 117 | /^[[:space:]]*# @internal/ { 118 | is_internal = 1 119 | } 120 | 121 | /^[[:space:]]*# @file/ { 122 | sub(/^[[:space:]]*# @file /, "") 123 | 124 | filedoc = render("h1", $0) "\n" 125 | if(style == "webdoc"){ 126 | filedoc = filedoc render("comment", "file=" $0) "\n" 127 | } 128 | 129 | } 130 | 131 | /^[[:space:]]*# @brief/ { 132 | sub(/^[[:space:]]*# @brief /, "") 133 | if(style == "webdoc"){ 134 | filedoc = filedoc render("comment", "brief=" $0) "\n" 135 | } 136 | filedoc = filedoc "\n" $0 137 | } 138 | 139 | /^[[:space:]]*# @description/ { 140 | in_description = 1 141 | in_example = 0 142 | 143 | reset() 144 | 145 | docblock = "" 146 | } 147 | 148 | in_description { 149 | if (/^[^[[:space:]]*#]|^[[:space:]]*# @[^d]|^[[:space:]]*[^#]/) { 150 | if (!match(content_desc, /\n$/)) { 151 | content_desc = content_desc "\n" 152 | } 153 | in_description = 0 154 | } else { 155 | sub(/^[[:space:]]*# @description /, "") 156 | sub(/^[[:space:]]*# /, "") 157 | sub(/^[[:space:]]*#$/, "") 158 | 159 | content_desc = content_desc "\n" $0 160 | } 161 | } 162 | 163 | in_example { 164 | 165 | if (! /^[[:space:]]*#[ ]{3}/) { 166 | 167 | in_example = 0 168 | 169 | content_example = content_example "\n" render("/code") "\n" 170 | } else { 171 | sub(/^[[:space:]]*#[ ]{3}/, "") 172 | 173 | content_example = content_example "\n" $0 174 | } 175 | } 176 | 177 | /^[[:space:]]*# @example/ { 178 | in_example = 1 179 | content_example = content_example "\n" render("h3", "Example") 180 | content_example = content_example "\n\n" render("code", "bash") 181 | } 182 | 183 | /^[[:space:]]*# @arg/ { 184 | if (!has_args) { 185 | has_args = 1 186 | 187 | content_args = content_args "\n" render("h3", "Arguments") "\n\n" 188 | } 189 | 190 | sub(/^[[:space:]]*# @arg /, "") 191 | 192 | $0 = render("argN", $0) 193 | $0 = render("arg@", $0) 194 | 195 | content_args = content_args render("li", $0) "\n" 196 | } 197 | 198 | /^[[:space:]]*# @noargs/ { 199 | content_args = content_args "\n" render("i", "Function has no arguments.") "\n" 200 | } 201 | 202 | /^[[:space:]]*# @exitcode/ { 203 | if (!has_exitcode) { 204 | has_exitcode = 1 205 | 206 | content_exitcode = content_exitcode "\n" render("h3", "Exit codes") "\n\n" 207 | } 208 | 209 | sub(/^[[:space:]]*# @exitcode /, "") 210 | 211 | $0 = render("exitcode", $0) 212 | 213 | content_exitcode = content_exitcode render("li", $0) "\n" 214 | } 215 | 216 | /^[[:space:]]*# @see/ { 217 | sub(/[[:space:]]*# @see /, "") 218 | anchor = generate_anchor($0) 219 | $0 = render_list($0, anchor) 220 | 221 | content_seealso = content_seealso "\n" render("h3", "See also") "\n\n" $0 "\n" 222 | } 223 | 224 | /^[[:space:]]*# @stdout/ { 225 | has_stdout = 1 226 | 227 | sub(/^[[:space:]]*# @stdout /, "") 228 | 229 | content_stdout = content_stdout "\n" render("h3", "Output on stdout") 230 | content_stdout = content_stdout "\n\n" render("li", $0) "\n" 231 | } 232 | 233 | { 234 | docblock = content_desc content_args content_exitcode content_stdout content_example content_seealso 235 | if(style == "webdoc"){ 236 | docblock = docblock "\n" render("h_rule") "\n" 237 | } 238 | } 239 | 240 | /^[ \t]*(function([ \t])+)?([a-zA-Z0-9_:-]+)([ \t]*)(\(([ \t]*)\))?[ \t]*\{/ && docblock != "" && !in_example { 241 | if (is_internal) { 242 | is_internal = 0 243 | } else { 244 | func_name = gensub(\ 245 | /^[ \t]*(function([ \t])+)?([a-zA-Z0-9_:-]+)[ \t]*\(.*/, \ 246 | "\\3()", \ 247 | "g" \ 248 | ) 249 | doc = doc "\n" render("h2", func_name) "\n" docblock 250 | if (toc) { 251 | url = generate_anchor(func_name) 252 | 253 | content_idx = content_idx "\n" "- [" func_name "](#" url ")" 254 | } 255 | } 256 | 257 | docblock = "" 258 | reset() 259 | } 260 | 261 | END { 262 | if (filedoc != "") { 263 | print filedoc 264 | } 265 | 266 | if (toc) { 267 | print "" 268 | print render("h2", "Table of Contents") 269 | print content_idx 270 | print "" 271 | print render("h_rule") 272 | } 273 | 274 | print doc 275 | } 276 | -------------------------------------------------------------------------------- /bin/generate_readme.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | #https://github.com/bkrem/make-toc.sh/blob/master/make-toc.sh 4 | #https://gitlab.com/pedrolab/doctoc.sh/-/blob/master/doctoc.sh 5 | _usage() { 6 | printf " 7 | Script to autogenerate markdown based on bash source code.\n 8 | The script generates table of contents and bashdoc and update the given markdown file.\n 9 | Usage:\n %s [options.. ]\n 10 | Options:\n 11 | -f | --file - Relative or absolute path to the README.md file. 12 | -s | --sh-dir - path to the bash script source folder to generate shdocs.\n 13 | -l | --toc-level - Minimum level of header to print in Table of Contents.\n 14 | -d | --toc-depth - Maximum depth of tree to print in Table of Contents.\n 15 | -w | --webdoc - Flag to indicate generation of webdoc.\n 16 | -p | --dest-dir - Path in which wedoc files must be generated.\n 17 | -h | --help - Display usage instructions.\n" "${0##*/}" 18 | exit 0 19 | } 20 | 21 | _setup_arguments() { 22 | 23 | unset MINLEVEL MAXLEVEL SCRIPT_FILE SOURCE_MARKDOWN SOURCE_SCRIPT_DIR SCRIPT_DIR WEBDOC WEBDOC_DEST_DIR 24 | MINLEVEL=1 25 | MAXLEVEL=3 26 | SCRIPT_FILE="${0##*/}" 27 | declare source="${BASH_SOURCE[0]}" 28 | while [ -h "$source" ]; do # resolve $source until the file is no longer a symlink 29 | SCRIPT_DIR="$(cd -P "$(dirname "$source")" > /dev/null 2>&1 && pwd)" 30 | source="$(readlink "$source")" 31 | [[ $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 32 | done 33 | SCRIPT_DIR="$(cd -P "$(dirname "$source")" > /dev/null 2>&1 && pwd)" 34 | SOURCE_MARKDOWN="${SCRIPT_DIR}/../README.md" 35 | SOURCE_SCRIPT_DIR="${SCRIPT_DIR}/../src" 36 | WEBDOC_DEST_DIR="${SCRIPT_DIR}/../hugo-docs/content/functions" 37 | 38 | SHORTOPTS="whp:f:m:d:s:-:" 39 | 40 | while getopts "${SHORTOPTS}" OPTION; do 41 | case "${OPTION}" in 42 | -) 43 | _check_longoptions() { { [[ -z "$1" ]] && printf '%s: --%s: option requires an argument\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1; } || :; } 44 | case "${OPTARG}" in 45 | help) 46 | _usage 47 | ;; 48 | file) 49 | _check_longoptions "${!OPTIND}" 50 | SOURCE_MARKDOWN="${!OPTIND}" && OPTIND=$((OPTIND + 1)) 51 | ;; 52 | toc-level) 53 | _check_longoptions "${!OPTIND}" 54 | MINLEVEL="${!OPTIND}" && OPTIND=$((OPTIND + 1)) 55 | ;; 56 | toc-depth) 57 | _check_longoptions "${!OPTIND}" 58 | MAXLEVEL="${!OPTIND}" && OPTIND=$((OPTIND + 1)) 59 | ;; 60 | sh-dir) 61 | _check_longoptions "${!OPTIND}" 62 | SOURCE_SCRIPT_DIR="${!OPTIND}" && OPTIND=$((OPTIND + 1)) 63 | ;; 64 | webdoc) 65 | WEBDOC=true 66 | ;; 67 | dest-dir) 68 | WEBDOC_DEST_DIR="${OPTARG}" 69 | ;; 70 | '') 71 | _usage 72 | ;; 73 | *) 74 | printf '%s: --%s: Unknown option\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1 75 | ;; 76 | esac 77 | ;; 78 | h) 79 | _usage 80 | ;; 81 | f) 82 | SOURCE_MARKDOWN="${OPTARG}" 83 | ;; 84 | m) 85 | MINLEVEL="${OPTARG}" 86 | ;; 87 | d) 88 | MAXLEVEL="${OPTARG}" 89 | ;; 90 | s) 91 | SOURCE_SCRIPT_DIR="${OPTARG}" 92 | ;; 93 | w) 94 | WEBDOC=true 95 | ;; 96 | p) 97 | WEBDOC_DEST_DIR="${OPTARG}" 98 | ;; 99 | :) 100 | printf '%s: -%s: option requires an argument\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1 101 | ;; 102 | ?) 103 | printf '%s: -%s: Unknown option\nTry '"%s -h/--help"' for more information.\n' "${0##*/}" "${OPTARG}" "${0##*/}" && exit 1 104 | ;; 105 | esac 106 | done 107 | shift "$((OPTIND - 1))" 108 | 109 | if [[ -w "${SOURCE_MARKDOWN}" ]]; then 110 | declare src_file src_extension 111 | src_file="${SOURCE_MARKDOWN##*/}" 112 | src_extension="${src_file##*.}" 113 | if [[ "${src_extension,,}" != "md" ]]; then 114 | printf "Provided file %s is not a markdown.\n" "${src_file}" && exit 1 115 | fi 116 | else 117 | printf "Provided file %s does not exist or no enough permission to access it.\n" "${SOURCE_MARKDOWN}" && exit 1 118 | fi 119 | 120 | if [[ ! -d "${SOURCE_SCRIPT_DIR}" ]]; then 121 | printf "Provided directory for bash script files %s does not exist.\n" "${SOURCE_SCRIPT_DIR}" && exit 1 122 | fi 123 | 124 | declare re='^[0-9]+$' 125 | if ! [[ "${MINLEVEL}" =~ $re ]] || ! [[ "${MAXLEVEL}" =~ $re ]]; then 126 | echo "error: Not a number" >&2 127 | exit 1 128 | fi 129 | if [[ "${MINLEVEL}" -gt "${MAXLEVEL}" ]]; then 130 | printf "Minimum level for TOC cannot be greater than the depth of TOC to be printed.\n" && exit 1 131 | fi 132 | 133 | [ -d "${WEBDOC_DEST_DIR}" ] || mkdir -p "${WEBDOC_DEST_DIR}" 134 | 135 | } 136 | 137 | _setup_tempfile() { 138 | declare temp_file 139 | type -p mktemp &> /dev/null && { temp_file="$(mktemp -u)" || temp_file="${PWD}/$((RANDOM * 2)).LOG"; } 140 | trap 'rm -f "${temp_file}"' EXIT 141 | printf "%s" "${temp_file}" 142 | } 143 | 144 | _generate_shdoc() { 145 | declare file 146 | file="$(realpath "${1}")" 147 | if [[ -s "${file}" ]]; then 148 | awk -v style="readme" -v toc=0 -f "${SCRIPT_DIR}"/bashdoc.awk < "${file}" >> "$2" 149 | #awk -v style="doc" -v toc=1 -f "${SCRIPT_DIR}"/bashdoc.awk < "${file}" >> "../docs/${file##*/}.md" 150 | fi 151 | } 152 | 153 | _insert_shdoc_to_file() { 154 | declare shdoc_tmp_file source_markdown start_shdoc info_shdoc end_shdoc 155 | shdoc_tmp_file="$1" 156 | source_markdown="$2" 157 | 158 | start_shdoc="" 159 | info_shdoc="" 160 | end_shdoc="" 161 | 162 | sed -i "1s/^/${info_shdoc}\n/" "${shdoc_tmp_file}" 163 | 164 | if grep --color=always -Pzl "(?s)${start_shdoc}.*\n.*${end_shdoc}" "${source_markdown}" &> /dev/null; then 165 | # src https://stackoverflow.com/questions/2699666/replace-delimited-block-of-text-in-file-with-the-contents-of-another-file 166 | 167 | sed -i -ne "/${start_shdoc}/ {p; r ${shdoc_tmp_file}" -e ":a; n; /${end_shdoc}/ {p; b}; ba}; p" "${source_markdown}" 168 | echo -e "Updated bashdoc content to ${source_markdown} successfully\n" 169 | 170 | else 171 | { 172 | printf "%s\n" "${start_shdoc}" 173 | cat "${shdoc_tmp_file}" 174 | printf "%s\n" "${end_shdoc}" 175 | } >> "${source_markdown}" 176 | echo -e "Created bashdoc content to ${source_markdown} successfully\n" 177 | fi 178 | } 179 | 180 | _process_sh_files() { 181 | declare shdoc_tmp_file source_script_dir source_markdown 182 | source_markdown="${1}" 183 | source_script_dir="${2}" 184 | shdoc_tmp_file=$(_setup_tempfile) 185 | find "${source_script_dir}" -name '*.sh' -print0 | sort -z | 186 | while IFS= read -r -d '' line; do 187 | _generate_shdoc "${line}" "${shdoc_tmp_file}" 188 | done 189 | _insert_shdoc_to_file "${shdoc_tmp_file}" "${source_markdown}" 190 | rm "${shdoc_tmp_file}" 191 | 192 | } 193 | 194 | _generate_toc() { 195 | 196 | declare line level title anchor output counter temp_output invalid_chars 197 | 198 | invalid_chars="'[]/?!:\`.,()*\";{}+=<>~$|#@&–—" 199 | while IFS='' read -r line || [[ -n "${line}" ]]; do 200 | level="$(echo "${line}" | sed -E 's/(#+).*/\1/; s/#/ /g; s/^ //')" 201 | title="$(echo "${line}" | sed -E 's/^#+ //')" 202 | [[ "${title}" = "Table of Contents" ]] && continue 203 | 204 | # 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 205 | anchor="$(echo "${title}" | tr '[:upper:] ' '[:lower:]-' | sed 's/[[:upper:]]*/\L&/' | tr -d "${invalid_chars}")" 206 | 207 | # check new line introduced is not duplicated, if is duplicated, introduce a number at the end 208 | temp_output=$output"$level- [$title](#$anchor)\n" 209 | counter=1 210 | while true; do 211 | nlines="$(echo -e "${temp_output}" | wc -l)" 212 | duplines="$(echo -e "${temp_output}" | sort | uniq | wc -l)" 213 | if [ "${nlines}" = "${duplines}" ]; then 214 | break 215 | fi 216 | temp_output=$output"$level- [$title](#$anchor-$counter)\n" 217 | counter=$((counter + 1)) 218 | done 219 | 220 | output="$temp_output" 221 | 222 | # grep: filter header candidates to be included in toc 223 | # sed: remove the ignored headers (case: minlevel greater than one) to avoid unnecessary spacing later in level variable assignment 224 | done <<< "$(grep -E "^#{${MINLEVEL},${MAXLEVEL}} " "${1}" | tr -d '\r' | sed "s/^#\{$((MINLEVEL - 1))\}//g")" 225 | 226 | # when in toc we have two `--` quit one 227 | echo "$output" 228 | 229 | } 230 | 231 | _insert_toc_to_file() { 232 | 233 | declare source_markdown toc_text start_toc info_toc end_toc toc_block utext_ampersand utext_slash 234 | source_markdown="${1}" 235 | toc_text="${2}" 236 | start_toc="" 237 | info_toc="" 238 | end_toc="" 239 | 240 | toc_block="$start_toc\n$info_toc\n## Table of Contents\n\n$toc_text\n$end_toc" 241 | # temporary replace of '/' (confused with separator of substitutions) and '&' (confused with match regex symbol) to run the special sed command 242 | utext_ampersand="id8234923000230gzz" 243 | utext_slash="id9992384923423gzz" 244 | toc_block="${toc_block//\&/${utext_ampersand}}" 245 | toc_block="${toc_block//\//${utext_slash}}" 246 | 247 | # search multiline toc block -> https://stackoverflow.com/questions/2686147/how-to-find-patterns-across-multiple-lines-using-grep/2686705 248 | # grep color for debugging -> https://superuser.com/questions/914856/grep-display-all-output-but-highlight-search-matches 249 | if grep --color=always -Pzl "(?s)${start_toc}.*\n.*${end_toc}" "${source_markdown}" &> /dev/null; then 250 | # src https://askubuntu.com/questions/533221/how-do-i-replace-multiple-lines-with-single-word-in-fileinplace-replace 251 | sed -i ":a;N;\$!ba;s/$start_toc.*$end_toc/$toc_block/g" "${source_markdown}" 252 | echo -e "Updated TOC content in ${source_markdown} succesfully\n" 253 | 254 | else 255 | sed -i 1i"$toc_block" "${source_markdown}" 256 | echo -e "Created TOC in ${source_markdown} succesfully\n" 257 | 258 | fi 259 | 260 | # undo symbol replacements 261 | sed -i "s,${utext_ampersand},\&,g" "${source_markdown}" 262 | sed -i "s,${utext_slash},\/,g" "${source_markdown}" 263 | 264 | } 265 | 266 | _process_toc() { 267 | declare toc_temp_file source_markdown level toc_text 268 | source_markdown="${1}" 269 | 270 | toc_temp_file=$(_setup_tempfile) 271 | 272 | sed '/```/,/```/d' "${source_markdown}" > "${toc_temp_file}" 273 | 274 | level=$MINLEVEL 275 | while [[ $(grep -Ec "^#{$level} " "${toc_temp_file}") -le 1 ]]; do 276 | level=$((level + 1)) 277 | done 278 | 279 | MINLEVEL=${level} 280 | toc_text=$(_generate_toc "${toc_temp_file}") 281 | rm "${toc_temp_file}" 282 | 283 | _insert_toc_to_file "${source_markdown}" "${toc_text}" 284 | } 285 | 286 | _generate_webdoc() { 287 | declare dest_dir filename file_basename dest_file_path shdoc_tmp_file is_new_file 288 | declare title description start_shdoc end_shdoc file_modified_date file_modified_date_epoc 289 | declare webdoc_lastmod_date webdoc_lastmod_epoc 290 | file="$(realpath "${1}")" 291 | dest_dir="${2}" 292 | 293 | filename="${file##*/}" 294 | file_basename="${filename%.*}" 295 | dest_file_path="${dest_dir}/${file_basename}.md" 296 | file_modified_date="$(date -r "${file}" +"%FT%T%:z")" 297 | file_modified_date_epoc="$(date -r "${file}" +"%s")" 298 | 299 | start_shdoc="" 300 | end_shdoc="" 301 | if [[ ! -f "${dest_file_path}" ]]; then 302 | 303 | cat << EOF > "${dest_file_path}" 304 | --- 305 | title : 306 | description : 307 | date : ${file_modified_date} 308 | lastmod : ${file_modified_date} 309 | --- 310 | ${start_shdoc} 311 | ${end_shdoc} 312 | EOF 313 | is_new_file=true 314 | else 315 | is_new_file=false 316 | webdoc_lastmod_date="$(sed -ne 's/-->//; s/^.*lastmod : //p' "${dest_file_path}")" 317 | webdoc_lastmod_epoc="$(date -d "${webdoc_lastmod_date}" +"%s")" 318 | fi 319 | 320 | if [[ "${is_new_file}" = true || "${file_modified_date_epoc}" -gt "${webdoc_lastmod_epoc}" ]]; then 321 | 322 | shdoc_tmp_file=$(_setup_tempfile) 323 | if [[ -s "${file}" ]]; then 324 | awk -v style="webdoc" -v toc=1 -f "${SCRIPT_DIR}"/bashdoc.awk < "${file}" >> "${shdoc_tmp_file}" 325 | fi 326 | 327 | if grep --color=always -Pzl "(?s)${start_shdoc}.*\n.*${end_shdoc}" "${dest_file_path}" &> /dev/null; then 328 | sed -i -ne "/${start_shdoc}/ {p; r ${shdoc_tmp_file}" -e ":a; n; /${end_shdoc}/ {p; b}; ba}; p" "${dest_file_path}" 329 | fi 330 | 331 | # Extract title and description from webdoc 332 | title="$(sed -ne 's/-->//; s/^.*//; s/^.*/${title}/g" "${dest_file_path}" 341 | sed -i -e "s//${description}/g" "${dest_file_path}" 342 | else 343 | sed -i -e "s/title : .*/title : ${title}/g" "${dest_file_path}" 344 | sed -i -e "s/description : .*/description : ${description}/g" "${dest_file_path}" 345 | 346 | fi 347 | 348 | # Update the last modified timestamp in front matter 349 | sed -i -e "s/lastmod : .*/lastmod : ${file_modified_date}/g" "${dest_file_path}" 350 | 351 | echo -e "Updated bashdoc content to ${dest_file_path} successfully." 352 | rm "${shdoc_tmp_file}" 353 | 354 | fi 355 | } 356 | _process_webdoc_files() { 357 | declare source_script_dir dest_dir 358 | 359 | source_script_dir="${1}" 360 | dest_dir="${2}" 361 | 362 | find "${source_script_dir}" -name '*.sh' -print0 | sort -z | 363 | while IFS= read -r -d '' line; do 364 | _generate_webdoc "${line}" "${dest_dir}" 365 | done 366 | } 367 | 368 | _count_library_functions() { 369 | declare source_script_dir 370 | source_script_dir="${1}" 371 | 372 | find "${source_script_dir}" -name '*.sh' -print0 | sort -z | 373 | { 374 | declare -i function_count=0 count=0 375 | while IFS= read -r -d '' line; do 376 | count=0 377 | count=$(grep -c '^[[:alpha:]]*::[[:alnum:]_]*()' "${line}") 378 | function_count=$((function_count + count)) 379 | done 380 | printf "Total library functions: %s \n" "${function_count}" 381 | 382 | } 383 | } 384 | main() { 385 | # export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' 386 | # set -x 387 | trap 'exit "$?"' INT TERM && trap 'exit "$?"' EXIT 388 | set -o errexit -o noclobber -o pipefail 389 | 390 | _setup_arguments "${@}" 391 | _process_sh_files "${SOURCE_MARKDOWN}" "${SOURCE_SCRIPT_DIR}" 392 | _process_toc "${SOURCE_MARKDOWN}" 393 | 394 | if [[ -n ${WEBDOC} ]]; then 395 | _process_webdoc_files "${SOURCE_SCRIPT_DIR}" "${WEBDOC_DEST_DIR}" 396 | fi 397 | _count_library_functions "${SOURCE_SCRIPT_DIR}" 398 | } 399 | 400 | main "${@}" 401 | -------------------------------------------------------------------------------- /image/bash-utility.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labbots/bash-utility/f9d3191abee7967c0d3b43d0b21607372408fdeb/image/bash-utility.png -------------------------------------------------------------------------------- /image/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/labbots/bash-utility/f9d3191abee7967c0d3b43d0b21607372408fdeb/image/logo.png -------------------------------------------------------------------------------- /src/array.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Array 4 | # @brief Functions for array operations and manipulations. 5 | 6 | # @description Check if item exists in the given array. 7 | # 8 | # @example 9 | # array=("a" "b" "c") 10 | # array::contains "c" ${array[@]} 11 | # #Output 12 | # 0 13 | # 14 | # @arg $1 mixed Item to search (needle). 15 | # @arg $2 array array to be searched (haystack). 16 | # 17 | # @exitcode 0 If successful. 18 | # @exitcode 1 If no match found in the array. 19 | # @exitcode 2 Function missing arguments. 20 | array::contains() { 21 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 22 | declare query="${1:-}" 23 | shift 24 | 25 | for element in "${@}"; do 26 | [[ "${element}" == "${query}" ]] && return 0 27 | done 28 | 29 | return 1 30 | } 31 | 32 | # @description Remove duplicate items from the array. 33 | # 34 | # @example 35 | # array=("a" "b" "a" "c") 36 | # printf "%s" "$(array::dedupe ${array[@]})" 37 | # #Output 38 | # a 39 | # b 40 | # c 41 | # 42 | # @arg $1 array Array to be deduped. 43 | # 44 | # @exitcode 0 If successful. 45 | # @exitcode 2 Function missing arguments. 46 | # 47 | # @stdout Deduplicated array. 48 | array::dedupe() { 49 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 50 | declare -A arr_tmp 51 | declare -a arr_unique 52 | for i in "$@"; do 53 | { [[ -z ${i} || ${arr_tmp[${i}]} ]]; } && continue 54 | arr_unique+=("${i}") && arr_tmp[${i}]=x 55 | done 56 | printf '%s\n' "${arr_unique[@]}" 57 | } 58 | 59 | # @description Check if a given array is empty. 60 | # 61 | # @example 62 | # array=("a" "b" "c" "d") 63 | # array::is_empty "${array[@]}" 64 | # 65 | # @arg $1 array Array to be checked. 66 | # 67 | # @exitcode 0 If the given array is empty. 68 | # @exitcode 2 If the given array is not empty. 69 | array::is_empty() { 70 | declare -a array 71 | local array=("$@") 72 | if [ ${#array[@]} -eq 0 ]; then 73 | return 0 74 | else 75 | return 1 76 | fi 77 | } 78 | # @description Join array elements with a string. 79 | # 80 | # @example 81 | # array=("a" "b" "c" "d") 82 | # printf "%s" "$(array::join "," "${array[@]}")" 83 | # #Output 84 | # a,b,c,d 85 | # printf "%s" "$(array::join "" "${array[@]}")" 86 | # #Output 87 | # abcd 88 | # 89 | # @arg $1 string String to join the array elements (glue). 90 | # @arg $2 array array to be joined with glue string. 91 | # 92 | # @exitcode 0 If successful. 93 | # @exitcode 2 Function missing arguments. 94 | # 95 | # @stdout String containing a string representation of all the array elements in the same order,with the glue string between each element. 96 | array::join() { 97 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 98 | declare delimiter="${1}" 99 | shift 100 | printf "%s" "${1}" 101 | shift 102 | printf "%s" "${@/#/${delimiter}}" 103 | } 104 | 105 | # @description Return an array with elements in reverse order. 106 | # 107 | # @example 108 | # array=(1 2 3 4 5) 109 | # printf "%s" "$(array::reverse "${array[@]}")" 110 | # #Output 111 | # 5 4 3 2 1 112 | # 113 | # @arg $1 array The input array. 114 | # 115 | # @exitcode 0 If successful. 116 | # @exitcode 2 Function missing arguments. 117 | # 118 | # @stdout The reversed array. 119 | array::reverse() { 120 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 121 | declare min=0 122 | declare -a array 123 | array=("$@") 124 | declare max=$((${#array[@]} - 1)) 125 | 126 | while [[ $min -lt $max ]]; do 127 | # Swap current first and last elements 128 | x="${array[$min]}" 129 | array[$min]="${array[$max]}" 130 | array[$max]="$x" 131 | 132 | # Move closer 133 | ((min++, max--)) 134 | done 135 | printf '%s\n' "${array[@]}" 136 | } 137 | 138 | # @description Returns a random item from the array. 139 | # 140 | # @example 141 | # array=("a" "b" "c" "d") 142 | # printf "%s\n" "$(array::random_element "${array[@]}")" 143 | # #Output 144 | # c 145 | # 146 | # @arg $1 array The input array. 147 | # 148 | # @exitcode 0 If successful. 149 | # @exitcode 2 Function missing arguments. 150 | # 151 | # @stdout Random item out of the array. 152 | array::random_element() { 153 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 154 | declare -a array 155 | local array=("$@") 156 | printf '%s\n' "${array[RANDOM % $#]}" 157 | } 158 | 159 | # @description Sort an array from lowest to highest. 160 | # 161 | # @example 162 | # sarr=("a c" "a" "d" 2 1 "4 5") 163 | # array::array_sort "${sarr[@]}" 164 | # #Output 165 | # 1 166 | # 2 167 | # 4 5 168 | # a 169 | # a c 170 | # d 171 | # 172 | # @arg $1 array The input array. 173 | # 174 | # @exitcode 0 If successful. 175 | # @exitcode 2 Function missing arguments. 176 | # 177 | # @stdout sorted array. 178 | array::sort() { 179 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 180 | declare -a array=("$@") 181 | declare -a sorted 182 | declare noglobtate 183 | noglobtate="$(shopt -po noglob)" 184 | set -o noglob 185 | declare IFS=$'\n' 186 | sorted=($(sort <<< "${array[*]}")) 187 | unset IFS 188 | eval "${noglobtate}" 189 | printf "%s\n" "${sorted[@]}" 190 | } 191 | 192 | # @description Sort an array in reverse order (highest to lowest). 193 | # 194 | # @example 195 | # sarr=("a c" "a" "d" 2 1 "4 5") 196 | # array::array_sort "${sarr[@]}" 197 | # #Output 198 | # d 199 | # a c 200 | # a 201 | # 4 5 202 | # 2 203 | # 1 204 | # 205 | # @arg $1 array The input array. 206 | # 207 | # @exitcode 0 If successful. 208 | # @exitcode 2 Function missing arguments. 209 | # 210 | # @stdout reverse sorted array. 211 | array::rsort() { 212 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 213 | declare -a array=("$@") 214 | declare -a sorted 215 | declare noglobtate 216 | noglobtate="$(shopt -po noglob)" 217 | set -o noglob 218 | declare IFS=$'\n' 219 | sorted=($(sort -r<<< "${array[*]}")) 220 | unset IFS 221 | eval "${noglobtate}" 222 | printf "%s\n" "${sorted[@]}" 223 | } 224 | 225 | # @description Bubble sort an integer array from lowest to highest. 226 | # This sort does not work on string array. 227 | # @example 228 | # iarr=(4 5 1 3) 229 | # array::bsort "${iarr[@]}" 230 | # #Output 231 | # 1 232 | # 3 233 | # 4 234 | # 5 235 | # 236 | # @arg $1 array The input array. 237 | # 238 | # @exitcode 0 If successful. 239 | # @exitcode 2 Function missing arguments. 240 | # 241 | # @stdout bubble sorted array. 242 | array::bsort() { 243 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 244 | declare tmp 245 | declare arr=("$@") 246 | for ((i = 0; i <= $((${#arr[@]} - 2)); ++i)); do 247 | for ((j = ((i + 1)); j <= ((${#arr[@]} - 1)); ++j)); do 248 | if [[ ${arr[i]} -gt ${arr[j]} ]]; then 249 | # echo $i $j ${arr[i]} ${arr[j]} 250 | tmp=${arr[i]} 251 | arr[i]=${arr[j]} 252 | arr[j]=$tmp 253 | fi 254 | done 255 | done 256 | printf "%s\n" "${arr[@]}" 257 | } 258 | 259 | # @description Merge two arrays. 260 | # Pass the variable name of the array instead of value of the variable. 261 | # @example 262 | # a=("a" "c") 263 | # b=("d" "c") 264 | # array::merge "a[@]" "b[@]" 265 | # #Output 266 | # a 267 | # c 268 | # d 269 | # c 270 | # 271 | # @arg $1 string variable name of first array. 272 | # @arg $2 string variable name of second array. 273 | # 274 | # @exitcode 0 If successful. 275 | # @exitcode 2 Function missing arguments. 276 | # 277 | # @stdout Merged array. 278 | array::merge() { 279 | [[ $# -ne 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 280 | declare -a arr1=("${!1}") 281 | declare -a arr2=("${!2}") 282 | declare out=("${arr1[@]}" "${arr2[@]}") 283 | printf "%s\n" "${out[@]}" 284 | } 285 | -------------------------------------------------------------------------------- /src/check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Check 4 | # @brief Helper functions. 5 | 6 | # @description Check if the command exists in the system. 7 | # 8 | # @example 9 | # check::command_exists "tput" 10 | # 11 | # @arg $1 string Command name to be searched. 12 | # 13 | # @exitcode 0 If the command exists. 14 | # @exitcode 1 If the command does not exist. 15 | # @exitcode 2 Function missing arguments. 16 | check::command_exists() { 17 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 18 | hash "${1}" 2> /dev/null 19 | } 20 | 21 | # @description Check if the script is executed with sudo privilege. 22 | # 23 | # @example 24 | # check::is_sudo 25 | # 26 | # @noargs 27 | # 28 | # @exitcode 0 If the script is executed with root privilege. 29 | # @exitcode 1 If the script is not executed with root privilege 30 | check::is_sudo() { 31 | if [[ $(id -u) -ne 0 ]]; then 32 | return 1 33 | fi 34 | } 35 | -------------------------------------------------------------------------------- /src/collection.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Collection 4 | # @brief (Experimental) Functions to iterates over a list of elements, yielding each in turn to an iteratee function. 5 | 6 | # @description Iterates over elements of collection and invokes iteratee for each element. 7 | # Input to the function can be a pipe output, here-string or file. 8 | # @example 9 | # test_func(){ 10 | # printf "print value: %s\n" "$1" 11 | # return 0 12 | # } 13 | # arr1=("a b" "c d" "a" "d") 14 | # printf "%s\n" "${arr1[@]}" | collection::each "test_func" 15 | # collection::each "test_func" < <(printf "%s\n" "${arr1[@]}") #alternative approach 16 | # #output 17 | # print value: a b 18 | # print value: c d 19 | # print value: a 20 | # print value: d 21 | # 22 | # @example 23 | # # If other function from this library is already used to process the array. 24 | # # Then following method could be used to pass the array to the function. 25 | # out=("$(array::dedupe "${arr1[@]}")") 26 | # collection::each "test_func" <<< "${out[@]}" 27 | # 28 | # @arg $1 string Iteratee function. 29 | # 30 | # @exitcode 0 If successful. 31 | # @exitcode 2 Function missing arguments. 32 | # @exitcode other exitcode returned by iteratee. 33 | # 34 | # @stdout Output of iteratee function. 35 | collection::each() { 36 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 37 | declare func="${1}" 38 | declare IFS=$'\n' 39 | while read -r it; do 40 | if [[ "${func}" == *"$"* ]]; then 41 | eval "${func}" 42 | else 43 | eval "${func}" "'${it}'" 44 | fi 45 | declare -i ret="$?" 46 | 47 | if [[ $ret -ne 0 ]]; then 48 | return $ret 49 | fi 50 | 51 | done 52 | } 53 | 54 | # @description Checks if iteratee function returns truthy for all elements of collection. Iteration is stopped once predicate returns false. 55 | # Input to the function can be a pipe output, here-string or file. 56 | # @example 57 | # arri=("1" "2" "3" "4") 58 | # printf "%s\n" "${arri[@]}" | collection::every "variable::is_numeric" 59 | # 60 | # @arg $1 string Iteratee function. 61 | # 62 | # @exitcode 0 If successful. 63 | # @exitcode 1 If iteratee function fails. 64 | # @exitcode 2 Function missing arguments. 65 | collection::every() { 66 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 67 | declare func="${1}" 68 | declare IFS=$'\n' 69 | while read -r it; do 70 | if [[ "${func}" == *"$"* ]]; then 71 | eval "${func}" 72 | else 73 | eval "${func}" "'${it}'" 74 | fi 75 | declare -i ret="$?" 76 | 77 | if [[ $ret -ne 0 ]]; then 78 | return 1 79 | fi 80 | 81 | done 82 | } 83 | 84 | # @description Iterates over elements of array, returning all elements where iteratee returns true. 85 | # Input to the function can be a pipe output, here-string or file. 86 | # @example 87 | # arri=("1" "2" "3" "a") 88 | # printf "%s\n" "${arri[@]}" | collection::filter "variable::is_numeric" 89 | # #output 90 | # 1 91 | # 2 92 | # 3 93 | # 94 | # @arg $1 string Iteratee function. 95 | # 96 | # @exitcode 0 If successful. 97 | # @exitcode 2 Function missing arguments. 98 | # 99 | # @stdout array values matching the iteratee function. 100 | collection::filter() { 101 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 102 | declare func="${1}" 103 | declare IFS=$'\n' 104 | while read -r it; do 105 | if [[ "${func}" == *"$"* ]]; then 106 | eval "${func}" 107 | else 108 | eval "${func}" "'${it}'" 109 | fi 110 | declare -i ret="$?" 111 | if [[ $ret = 0 ]]; then 112 | printf "%s\n" "${it}" 113 | fi 114 | done 115 | } 116 | 117 | # @description Iterates over elements of collection, returning the first element where iteratee returns true. 118 | # Input to the function can be a pipe output, here-string or file. 119 | # @example 120 | # arr=("1" "2" "3" "a") 121 | # check_a(){ 122 | # [[ "$1" = "a" ]] 123 | # } 124 | # printf "%s\n" "${arr[@]}" | collection::find "check_a" 125 | # #Output 126 | # a 127 | # 128 | # @arg $1 string Iteratee function. 129 | # 130 | # @exitcode 0 If successful. 131 | # @exitcode 1 If no match found. 132 | # @exitcode 2 Function missing arguments. 133 | # 134 | # @stdout first array value matching the iteratee function. 135 | collection::find() { 136 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 137 | declare func="${1}" 138 | declare IFS=$'\n' 139 | while read -r it; do 140 | 141 | if [[ "${func}" == *"$"* ]]; then 142 | eval "${func}" 143 | else 144 | eval "${func}" "'${it}'" 145 | fi 146 | declare -i ret="$?" 147 | if [[ $ret = 0 ]]; then 148 | printf "%s" "${it}" 149 | return 0 150 | fi 151 | done 152 | 153 | return 1 154 | } 155 | 156 | # @description Invokes the iteratee with each element passed as argument to the iteratee. 157 | # Input to the function can be a pipe output, here-string or file. 158 | # @example 159 | # opt=("-a" "-l") 160 | # printf "%s\n" "${opt[@]}" | collection::invoke "ls" 161 | # 162 | # @arg $1 string Iteratee function. 163 | # 164 | # @exitcode 0 If successful. 165 | # @exitcode 2 Function missing arguments. 166 | # @exitcode other exitcode returned by iteratee. 167 | # 168 | # @stdout Output from the iteratee function. 169 | collection::invoke() { 170 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 171 | declare -a args=() 172 | declare func="${1}" 173 | while read -r it; do 174 | args=("${args[@]}" "$it") 175 | done 176 | 177 | eval "${func}" "${args[@]}" 178 | } 179 | 180 | # @description Creates an array of values by running each element in array through iteratee. 181 | # Input to the function can be a pipe output, here-string or file. 182 | # @example 183 | # arri=("1" "2" "3") 184 | # add_one(){ 185 | # i=${1} 186 | # i=$(( i + 1 )) 187 | # printf "%s\n" "$i" 188 | # } 189 | # printf "%s\n" "${arri[@]}" | collection::map "add_one" 190 | # 191 | # @arg $1 string Iteratee function. 192 | # 193 | # @exitcode 0 If successful. 194 | # @exitcode 2 Function missing arguments. 195 | # @exitcode other exitcode returned by iteratee. 196 | # 197 | # @stdout Output result of iteratee on value. 198 | collection::map() { 199 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 200 | declare func="${1}" 201 | declare IFS=$'\n' 202 | declare out 203 | 204 | while read -r it; do 205 | 206 | if [[ "${func}" == *"$"* ]]; then 207 | out="$("${func}")" 208 | else 209 | out="$("${func}" "$it")" 210 | fi 211 | 212 | declare -i ret=$? 213 | 214 | if [[ $ret -ne 0 ]]; then 215 | return $ret 216 | fi 217 | 218 | printf "%s\n" "${out}" 219 | done 220 | } 221 | 222 | # @description The opposite of filter function; this method returns the elements of collection that iteratee does not return true. 223 | # Input to the function can be a pipe output, here-string or file. 224 | # @example 225 | # arri=("1" "2" "3" "a") 226 | # printf "%s\n" "${arri[@]}" | collection::reject "variable::is_numeric" 227 | # #Ouput 228 | # a 229 | # 230 | # @arg $1 string Iteratee function. 231 | # 232 | # @exitcode 0 If successful. 233 | # @exitcode 2 Function missing arguments. 234 | # 235 | # @stdout array values not matching the iteratee function. 236 | # @see collection::filter 237 | collection::reject() { 238 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 239 | declare func="${1}" 240 | declare IFS=$'\n' 241 | while read -r it; do 242 | 243 | if [[ "${func}" == *"$"* ]]; then 244 | eval "${func}" 245 | else 246 | eval "${func}" "'$it'" 247 | fi 248 | declare -i ret=$? 249 | if [[ $ret -ne 0 ]]; then 250 | echo "$it" 251 | fi 252 | 253 | done 254 | } 255 | 256 | # @description Checks if iteratee returns true for any element of the array. 257 | # Input to the function can be a pipe output, here-string or file. 258 | # @example 259 | # arr=("a" "b" "3" "a") 260 | # printf "%s\n" "${arr[@]}" | collection::reject "variable::is_numeric" 261 | # 262 | # @arg $1 string Iteratee function. 263 | # 264 | # @exitcode 0 If match successful. 265 | # @exitcode 1 If no match found. 266 | # @exitcode 2 Function missing arguments. 267 | collection::some() { 268 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 269 | declare func="${1}" 270 | declare IFS=$'\n' 271 | while read -r it; do 272 | 273 | if [[ "${func}" == *"$"* ]]; then 274 | eval "${func}" 275 | else 276 | eval "${func}" "'$it'" 277 | fi 278 | 279 | declare -i ret=$? 280 | 281 | if [[ $ret -eq 0 ]]; then 282 | return 0 283 | fi 284 | done 285 | 286 | return 1 287 | } 288 | -------------------------------------------------------------------------------- /src/date.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Date 4 | # @brief Functions for manipulating dates. 5 | 6 | # @description Get current time in unix timestamp. 7 | # 8 | # @example 9 | # echo "$(date::now)" 10 | # #Output 11 | # 1591554426 12 | # 13 | # @noargs 14 | # 15 | # @exitcode 0 If successful. 16 | # @exitcode 1 If unable to generate timestamp. 17 | # 18 | # @stdout current timestamp. 19 | date::now() { 20 | declare now 21 | now="$(date --universal +%s)" || return $? 22 | printf "%s" "${now}" 23 | } 24 | 25 | # @description convert datetime string to unix timestamp. 26 | # 27 | # @example 28 | # echo "$(date::epoc "2020-07-07 18:38")" 29 | # #Output 30 | # 1594143480 31 | # 32 | # @arg $1 string date time in any format. 33 | # 34 | # @exitcode 0 If successful. 35 | # @exitcode 1 If unable to generate timestamp. 36 | # @exitcode 2 Function missing arguments. 37 | # 38 | # @stdout timestamp for specified datetime. 39 | date::epoc() { 40 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 41 | 42 | declare date 43 | date=$(date -d "${1}" +"%s") || return $? 44 | printf "%s" "${date}" 45 | } 46 | 47 | # @description Add number of days from specified timestamp. 48 | # If number of days not specified then it defaults to 1 day. 49 | # 50 | # @example 51 | # echo "$(date::add_days_from "1594143480")" 52 | # #Output 53 | # 1594229880 54 | # 55 | # @arg $1 int unix timestamp. 56 | # @arg $2 int number of days (optional). 57 | # 58 | # @exitcode 0 If successful. 59 | # @exitcode 1 If unable to generate timestamp. 60 | # @exitcode 2 Function missing arguments. 61 | # 62 | # @stdout timestamp. 63 | date::add_days_from() { 64 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 65 | 66 | declare timestamp new_timestamp day 67 | timestamp="${1}" 68 | day=${2:-1} 69 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T')+${day} day" +'%s')" || return $? 70 | printf "%s" "${new_timestamp}" 71 | } 72 | 73 | # @description Add number of months from specified timestamp. 74 | # If number of months not specified then it defaults to 1 month. 75 | # 76 | # @example 77 | # echo "$(date::add_months_from "1594143480")" 78 | # #Output 79 | # 1596821880 80 | # 81 | # @arg $1 int unix timestamp. 82 | # @arg $2 int number of months (optional). 83 | # 84 | # @exitcode 0 If successful. 85 | # @exitcode 1 If unable to generate timestamp. 86 | # @exitcode 2 Function missing arguments. 87 | # 88 | # @stdout timestamp. 89 | date::add_months_from() { 90 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 91 | 92 | declare timestamp new_timestamp month 93 | timestamp="${1}" 94 | month=${2:-1} 95 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T')+${month} month" +'%s')" || return $? 96 | printf "%s" "${new_timestamp}" 97 | } 98 | 99 | # @description Add number of years from specified timestamp. 100 | # If number of years not specified then it defaults to 1 year. 101 | # 102 | # @example 103 | # echo "$(date::add_years_from "1594143480")" 104 | # #Output 105 | # 1625679480 106 | # 107 | # @arg $1 int unix timestamp. 108 | # @arg $2 int number of years (optional). 109 | # 110 | # @exitcode 0 If successful. 111 | # @exitcode 1 If unable to generate timestamp. 112 | # @exitcode 2 Function missing arguments. 113 | # 114 | # @stdout timestamp. 115 | date::add_years_from() { 116 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 117 | 118 | declare timestamp new_timestamp year 119 | timestamp="${1}" 120 | year=${2:-1} 121 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T')+${year} year" +'%s')" || return $? 122 | printf "%s" "${new_timestamp}" 123 | } 124 | 125 | # @description Add number of weeks from specified timestamp. 126 | # If number of weeks not specified then it defaults to 1 week. 127 | # 128 | # @example 129 | # echo "$(date::add_weeks_from "1594143480")" 130 | # #Output 131 | # 1594748280 132 | # 133 | # @arg $1 int unix timestamp. 134 | # @arg $2 int number of weeks (optional). 135 | # 136 | # @exitcode 0 If successful. 137 | # @exitcode 1 If unable to generate timestamp. 138 | # @exitcode 2 Function missing arguments. 139 | # 140 | # @stdout timestamp. 141 | date::add_weeks_from() { 142 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 143 | 144 | declare timestamp new_timestamp week 145 | timestamp="${1}" 146 | week=${2:-1} 147 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T')+${week} week" +'%s')" || return $? 148 | printf "%s" "${new_timestamp}" 149 | } 150 | 151 | # @description Add number of hours from specified timestamp. 152 | # If number of hours not specified then it defaults to 1 hour. 153 | # 154 | # @example 155 | # echo "$(date::add_hours_from "1594143480")" 156 | # #Output 157 | # 1594147080 158 | # 159 | # @arg $1 int unix timestamp. 160 | # @arg $2 int number of hours (optional). 161 | # 162 | # @exitcode 0 If successful. 163 | # @exitcode 1 If unable to generate timestamp. 164 | # @exitcode 2 Function missing arguments. 165 | # 166 | # @stdout timestamp. 167 | date::add_hours_from() { 168 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 169 | 170 | declare timestamp new_timestamp hour 171 | timestamp="${1}" 172 | hour=${2:-1} 173 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T')+${hour} hour" +'%s')" || return $? 174 | printf "%s" "${new_timestamp}" 175 | } 176 | 177 | # @description Add number of minutes from specified timestamp. 178 | # If number of minutes not specified then it defaults to 1 minute. 179 | # 180 | # @example 181 | # echo "$(date::add_minutes_from "1594143480")" 182 | # #Output 183 | # 1594143540 184 | # 185 | # @arg $1 int unix timestamp. 186 | # @arg $2 int number of minutes (optional). 187 | # 188 | # @exitcode 0 If successful. 189 | # @exitcode 1 If unable to generate timestamp. 190 | # @exitcode 2 Function missing arguments. 191 | # 192 | # @stdout timestamp. 193 | date::add_minutes_from() { 194 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 195 | 196 | declare timestamp new_timestamp minute 197 | timestamp="${1}" 198 | minute=${2:-1} 199 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T')+${minute} minute" +'%s')" || return $? 200 | printf "%s" "${new_timestamp}" 201 | } 202 | 203 | # @description Add number of seconds from specified timestamp. 204 | # If number of seconds not specified then it defaults to 1 second. 205 | # 206 | # @example 207 | # echo "$(date::add_seconds_from "1594143480")" 208 | # #Output 209 | # 1594143481 210 | # 211 | # @arg $1 int unix timestamp. 212 | # @arg $2 int number of seconds (optional). 213 | # 214 | # @exitcode 0 If successful. 215 | # @exitcode 1 If unable to generate timestamp. 216 | # @exitcode 2 Function missing arguments. 217 | # 218 | # @stdout timestamp. 219 | date::add_seconds_from() { 220 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 221 | 222 | declare timestamp new_timestamp minute 223 | timestamp="${1}" 224 | second=${2:-1} 225 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T')+${second} second" +'%s')" || return $? 226 | printf "%s" "${new_timestamp}" 227 | } 228 | 229 | # @description Add number of days from current day timestamp. 230 | # If number of days not specified then it defaults to 1 day. 231 | # 232 | # @example 233 | # echo "$(date::add_days "1")" 234 | # #Output 235 | # 1591640826 236 | # 237 | # @arg $1 int number of days (optional). 238 | # 239 | # @exitcode 0 If successful. 240 | # @exitcode 1 If unable to generate timestamp. 241 | # 242 | # @stdout timestamp. 243 | date::add_days() { 244 | declare timestamp new_timestamp day 245 | timestamp="$(date::now)" 246 | day=${1:-1} 247 | new_timestamp="$(date::add_days_from "${timestamp}" "${second}")" || return $? 248 | printf "%s" "${new_timestamp}" 249 | } 250 | 251 | # @description Add number of months from current day timestamp. 252 | # If number of months not specified then it defaults to 1 month. 253 | # 254 | # @example 255 | # echo "$(date::add_months "1")" 256 | # #Output 257 | # 1594146426 258 | # 259 | # @arg $1 int number of months (optional). 260 | # 261 | # @exitcode 0 If successful. 262 | # @exitcode 1 If unable to generate timestamp. 263 | # 264 | # @stdout timestamp. 265 | date::add_months() { 266 | declare timestamp new_timestamp month 267 | timestamp="$(date::now)" 268 | month=${1:-1} 269 | new_timestamp="$(date::add_months_from "${timestamp}" "${second}")" || return $? 270 | printf "%s" "${new_timestamp}" 271 | } 272 | 273 | # @description Add number of years from current day timestamp. 274 | # If number of years not specified then it defaults to 1 year. 275 | # 276 | # @example 277 | # echo "$(date::add_years "1")" 278 | # #Output 279 | # 1623090426 280 | # 281 | # @arg $1 int number of years (optional). 282 | # 283 | # @exitcode 0 If successful. 284 | # @exitcode 1 If unable to generate timestamp. 285 | # 286 | # @stdout timestamp. 287 | date::add_years() { 288 | declare timestamp new_timestamp year 289 | timestamp="$(date::now)" 290 | year=${1:-1} 291 | new_timestamp="$(date::add_years_from "${timestamp}" "${second}")" || return $? 292 | printf "%s" "${new_timestamp}" 293 | } 294 | 295 | # @description Add number of weeks from current day timestamp. 296 | # If number of weeks not specified then it defaults to 1 year. 297 | # 298 | # @example 299 | # echo "$(date::add_weeks "1")" 300 | # #Output 301 | # 1592159226 302 | # 303 | # @arg $1 int number of weeks (optional). 304 | # 305 | # @exitcode 0 If successful. 306 | # @exitcode 1 If unable to generate timestamp. 307 | # 308 | # @stdout timestamp. 309 | date::add_weeks() { 310 | declare timestamp new_timestamp week 311 | timestamp="$(date::now)" 312 | week=${1:-1} 313 | new_timestamp="$(date::add_weeks_from "${timestamp}" "${second}")" || return $? 314 | printf "%s" "${new_timestamp}" 315 | } 316 | 317 | # @description Add number of hours from current day timestamp. 318 | # If number of hours not specified then it defaults to 1 hour. 319 | # 320 | # @example 321 | # echo "$(date::add_hours "1")" 322 | # #Output 323 | # 1591558026 324 | # 325 | # @arg $1 int number of hours (optional). 326 | # 327 | # @exitcode 0 If successful. 328 | # @exitcode 1 If unable to generate timestamp. 329 | # 330 | # @stdout timestamp. 331 | date::add_hours() { 332 | declare timestamp new_timestamp hour 333 | timestamp="$(date::now)" 334 | hour=${1:-1} 335 | new_timestamp="$(date::add_hours_from "${timestamp}" "${second}")" || return $? 336 | printf "%s" "${new_timestamp}" 337 | } 338 | 339 | # @description Add number of minutes from current day timestamp. 340 | # If number of minutes not specified then it defaults to 1 minute. 341 | # 342 | # @example 343 | # echo "$(date::add_minutes "1")" 344 | # #Output 345 | # 1591554486 346 | # 347 | # @arg $2 int number of minutes (optional). 348 | # 349 | # @exitcode 0 If successful. 350 | # @exitcode 1 If unable to generate timestamp. 351 | # 352 | # @stdout timestamp. 353 | date::add_minutes() { 354 | declare timestamp new_timestamp minute 355 | timestamp="$(date::now)" 356 | minute=${1:-1} 357 | new_timestamp="$(date::add_minutes_from "${timestamp}" "${second}")" || return $? 358 | printf "%s" "${new_timestamp}" 359 | } 360 | 361 | # @description Add number of seconds from current day timestamp. 362 | # If number of seconds not specified then it defaults to 1 second. 363 | # 364 | # @example 365 | # echo "$(date::add_seconds "1")" 366 | # #Output 367 | # 1591554427 368 | # 369 | # @arg $2 int number of seconds (optional). 370 | # 371 | # @exitcode 0 If successful. 372 | # @exitcode 1 If unable to generate timestamp. 373 | # 374 | # @stdout timestamp. 375 | date::add_seconds() { 376 | declare timestamp new_timestamp minute 377 | timestamp="$(date::now)" 378 | second=${1:-1} 379 | new_timestamp="$(date::add_seconds_from "${timestamp}" "${second}")" || return $? 380 | printf "%s" "${new_timestamp}" 381 | } 382 | 383 | # @description Subtract number of days from specified timestamp. 384 | # If number of days not specified then it defaults to 1 day. 385 | # 386 | # @example 387 | # echo "$(date::sub_days_from "1594143480")" 388 | # #Output 389 | # 1594057080 390 | # 391 | # @arg $1 int unix timestamp. 392 | # @arg $2 int number of days (optional). 393 | # 394 | # @exitcode 0 If successful. 395 | # @exitcode 1 If unable to generate timestamp. 396 | # @exitcode 2 Function missing arguments. 397 | # 398 | # @stdout timestamp. 399 | date::sub_days_from() { 400 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 401 | 402 | declare timestamp new_timestamp day 403 | timestamp="${1}" 404 | day=${2:-1} 405 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T') ${day} days ago" +'%s')" || return $? 406 | printf "%s" "${new_timestamp}" 407 | } 408 | 409 | # @description Subtract number of months from specified timestamp. 410 | # If number of months not specified then it defaults to 1 month. 411 | # 412 | # @example 413 | # echo "$(date::sub_months_from "1594143480")" 414 | # #Output 415 | # 1591551480 416 | # 417 | # @arg $1 int unix timestamp. 418 | # @arg $2 int number of months (optional). 419 | # 420 | # @exitcode 0 If successful. 421 | # @exitcode 1 If unable to generate timestamp. 422 | # @exitcode 2 Function missing arguments. 423 | # 424 | # @stdout timestamp. 425 | date::sub_months_from() { 426 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 427 | 428 | declare timestamp new_timestamp month 429 | timestamp="${1}" 430 | month=${2:-1} 431 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T') ${month} months ago" +'%s')" || return $? 432 | printf "%s" "${new_timestamp}" 433 | } 434 | 435 | # @description Subtract number of years from specified timestamp. 436 | # If number of years not specified then it defaults to 1 year. 437 | # 438 | # @example 439 | # echo "$(date::sub_years_from "1594143480")" 440 | # #Output 441 | # 1562521080 442 | # 443 | # @arg $1 int unix timestamp. 444 | # @arg $2 int number of years (optional). 445 | # 446 | # @exitcode 0 If successful. 447 | # @exitcode 1 If unable to generate timestamp. 448 | # @exitcode 2 Function missing arguments. 449 | # 450 | # @stdout timestamp. 451 | date::sub_years_from() { 452 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 453 | 454 | declare timestamp new_timestamp year 455 | timestamp="${1}" 456 | year=${2:-1} 457 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T') ${year} years ago" +'%s')" || return $? 458 | printf "%s" "${new_timestamp}" 459 | } 460 | 461 | # @description Subtract number of weeks from specified timestamp. 462 | # If number of weeks not specified then it defaults to 1 week. 463 | # 464 | # @example 465 | # echo "$(date::sub_weeks_from "1594143480")" 466 | # #Output 467 | # 1593538680 468 | # 469 | # @arg $1 int unix timestamp. 470 | # @arg $2 int number of weeks (optional). 471 | # 472 | # @exitcode 0 If successful. 473 | # @exitcode 1 If unable to generate timestamp. 474 | # @exitcode 2 Function missing arguments. 475 | # 476 | # @stdout timestamp. 477 | date::sub_weeks_from() { 478 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 479 | 480 | declare timestamp new_timestamp week 481 | timestamp="${1}" 482 | week=${2:-1} 483 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T') ${week} weeks ago" +'%s')" || return $? 484 | printf "%s" "${new_timestamp}" 485 | } 486 | 487 | # @description Subtract number of hours from specified timestamp. 488 | # If number of hours not specified then it defaults to 1 hour. 489 | # 490 | # @example 491 | # echo "$(date::sub_hours_from "1594143480")" 492 | # #Output 493 | # 1594139880 494 | # 495 | # @arg $1 int unix timestamp. 496 | # @arg $2 int number of hours (optional). 497 | # 498 | # @exitcode 0 If successful. 499 | # @exitcode 1 If unable to generate timestamp. 500 | # @exitcode 2 Function missing arguments. 501 | # 502 | # @stdout timestamp. 503 | date::sub_hours_from() { 504 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 505 | 506 | declare timestamp new_timestamp hour 507 | timestamp="${1}" 508 | hour=${2:-1} 509 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T') ${hour} hours ago" +'%s')" || return $? 510 | printf "%s" "${new_timestamp}" 511 | } 512 | 513 | # @description Subtract number of minutes from specified timestamp. 514 | # If number of minutes not specified then it defaults to 1 minute. 515 | # 516 | # @example 517 | # echo "$(date::sub_minutes_from "1594143480")" 518 | # #Output 519 | # 1594143420 520 | # 521 | # @arg $1 int unix timestamp. 522 | # @arg $2 int number of minutes (optional). 523 | # 524 | # @exitcode 0 If successful. 525 | # @exitcode 1 If unable to generate timestamp. 526 | # @exitcode 2 Function missing arguments. 527 | # 528 | # @stdout timestamp. 529 | date::sub_minutes_from() { 530 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 531 | 532 | declare timestamp new_timestamp minute 533 | timestamp="${1}" 534 | minute=${2:-1} 535 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T') ${minute} minutes ago" +'%s')" || return $? 536 | printf "%s" "${new_timestamp}" 537 | } 538 | 539 | # @description Subtract number of seconds from specified timestamp. 540 | # If number of seconds not specified then it defaults to 1 second. 541 | # 542 | # @example 543 | # echo "$(date::sub_seconds_from "1594143480")" 544 | # #Output 545 | # 1594143479 546 | # 547 | # @arg $1 int unix timestamp. 548 | # @arg $2 int number of seconds (optional). 549 | # 550 | # @exitcode 0 If successful. 551 | # @exitcode 1 If unable to generate timestamp. 552 | # @exitcode 2 Function missing arguments. 553 | # 554 | # @stdout timestamp. 555 | date::sub_seconds_from() { 556 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 557 | 558 | declare timestamp new_timestamp minute 559 | timestamp="${1}" 560 | second=${2:-1} 561 | new_timestamp="$(date -d "$(date -d "@${timestamp}" '+%F %T') ${second} seconds ago" +'%s')" || return $? 562 | printf "%s" "${new_timestamp}" 563 | } 564 | 565 | # @description Subtract number of days from current day timestamp. 566 | # If number of days not specified then it defaults to 1 day. 567 | # 568 | # @example 569 | # echo "$(date::sub_days "1")" 570 | # #Output 571 | # 1588876026 572 | # 573 | # @arg $1 int number of days (optional). 574 | # 575 | # @exitcode 0 If successful. 576 | # @exitcode 1 If unable to generate timestamp. 577 | # 578 | # @stdout timestamp. 579 | date::sub_days() { 580 | declare timestamp new_timestamp day 581 | timestamp="$(date::now)" 582 | day=${1:-1} 583 | new_timestamp="$(date::sub_days_from "${timestamp}" "${second}")" || return $? 584 | printf "%s" "${new_timestamp}" 585 | } 586 | 587 | # @description Subtract number of months from current day timestamp. 588 | # If number of months not specified then it defaults to 1 month. 589 | # 590 | # @example 591 | # echo "$(date::sub_months "1")" 592 | # #Output 593 | # 1559932026 594 | # 595 | # @arg $1 int number of months (optional). 596 | # 597 | # @exitcode 0 If successful. 598 | # @exitcode 1 If unable to generate timestamp. 599 | # 600 | # @stdout timestamp. 601 | date::sub_months() { 602 | declare timestamp new_timestamp month 603 | timestamp="$(date::now)" 604 | month=${1:-1} 605 | new_timestamp="$(date::sub_months_from "${timestamp}" "${second}")" || return $? 606 | printf "%s" "${new_timestamp}" 607 | } 608 | 609 | # @description Subtract number of years from current day timestamp. 610 | # If number of years not specified then it defaults to 1 year. 611 | # 612 | # @example 613 | # echo "$(date::sub_years "1")" 614 | # #Output 615 | # 1591468026 616 | # 617 | # @arg $1 int number of years (optional). 618 | # 619 | # @exitcode 0 If successful. 620 | # @exitcode 1 If unable to generate timestamp. 621 | # 622 | # @stdout timestamp. 623 | date::sub_years() { 624 | declare timestamp new_timestamp year 625 | timestamp="$(date::now)" 626 | year=${1:-1} 627 | new_timestamp="$(date::sub_years_from "${timestamp}" "${second}")" || return $? 628 | printf "%s" "${new_timestamp}" 629 | } 630 | 631 | # @description Subtract number of weeks from current day timestamp. 632 | # If number of weeks not specified then it defaults to 1 week. 633 | # 634 | # @example 635 | # echo "$(date::sub_weeks "1")" 636 | # #Output 637 | # 1590949626 638 | # 639 | # @arg $1 int number of weeks (optional). 640 | # 641 | # @exitcode 0 If successful. 642 | # @exitcode 1 If unable to generate timestamp. 643 | # 644 | # @stdout timestamp. 645 | date::sub_weeks() { 646 | declare timestamp new_timestamp week 647 | timestamp="$(date::now)" 648 | week=${1:-1} 649 | new_timestamp="$(date::sub_weeks_from "${timestamp}" "${second}")" || return $? 650 | printf "%s" "${new_timestamp}" 651 | } 652 | 653 | # @description Subtract number of hours from current day timestamp. 654 | # If number of hours not specified then it defaults to 1 hour. 655 | # 656 | # @example 657 | # echo "$(date::sub_hours "1")" 658 | # #Output 659 | # 1591550826 660 | # 661 | # @arg $1 int number of hours (optional). 662 | # 663 | # @exitcode 0 If successful. 664 | # @exitcode 1 If unable to generate timestamp. 665 | # 666 | # @stdout timestamp. 667 | date::sub_hours() { 668 | declare timestamp new_timestamp hour 669 | timestamp="$(date::now)" 670 | hour=${1:-1} 671 | new_timestamp="$(date::sub_hours_from "${timestamp}" "${second}")" || return $? 672 | printf "%s" "${new_timestamp}" 673 | } 674 | 675 | # @description Subtract number of minutes from current day timestamp. 676 | # If number of minutes not specified then it defaults to 1 minute. 677 | # 678 | # @example 679 | # echo "$(date::sub_minutes "1")" 680 | # #Output 681 | # 1591554366 682 | # 683 | # @arg $1 int number of minutes (optional). 684 | # 685 | # @exitcode 0 If successful. 686 | # @exitcode 1 If unable to generate timestamp. 687 | # 688 | # @stdout timestamp. 689 | date::sub_minutes() { 690 | declare timestamp new_timestamp minute 691 | timestamp="$(date::now)" 692 | minute=${1:-1} 693 | new_timestamp="$(date::sub_minutes_from "${timestamp}" "${second}")" || return $? 694 | printf "%s" "${new_timestamp}" 695 | } 696 | 697 | # @description Subtract number of seconds from current day timestamp. 698 | # If number of seconds not specified then it defaults to 1 second. 699 | # 700 | # @example 701 | # echo "$(date::sub_seconds "1")" 702 | # #Output 703 | # 1591554425 704 | # 705 | # @arg $1 int number of seconds (optional). 706 | # 707 | # @exitcode 0 If successful. 708 | # @exitcode 1 If unable to generate timestamp. 709 | # 710 | # @stdout timestamp. 711 | date::sub_seconds() { 712 | declare timestamp new_timestamp minute 713 | timestamp="$(date::now)" 714 | second=${1:-1} 715 | new_timestamp="$(date::sub_seconds_from "${timestamp}" "${second}")" || return $? 716 | printf "%s" "${new_timestamp}" 717 | } 718 | 719 | # @description Format unix timestamp to human readable format. 720 | # If format string is not specified then it defaults to "yyyy-mm-dd hh:mm:ss" format. 721 | # 722 | # @example 723 | # echo echo "$(date::format "1594143480")" 724 | # #Output 725 | # 2020-07-07 18:38:00 726 | # 727 | # @arg $1 int unix timestamp. 728 | # @arg $2 string format control characters based on `date` command (optional). 729 | # 730 | # @exitcode 0 If successful. 731 | # @exitcode 1 If unable to generate time string. 732 | # @exitcode 2 Function missing arguments. 733 | # 734 | # @stdout formatted time string. 735 | date::format() { 736 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 737 | 738 | declare timestamp format out 739 | timestamp="${1}" 740 | format="${2:-"%F %T"}" 741 | out="$(date -d "@${timestamp}" +"${format}")" || return $? 742 | printf "%s" "${out}" 743 | 744 | } 745 | -------------------------------------------------------------------------------- /src/debug.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Debug 4 | # @brief Functions to facilitate debugging scripts. 5 | 6 | # @description Prints the content of array as key value pair for easier debugging. 7 | # Pass the variable name of the array instead of value of the variable. 8 | # @example 9 | # array=(foo bar baz) 10 | # printf "Array\n" 11 | # printarr "array" 12 | # declare -A assoc_array 13 | # assoc_array=([foo]=bar [baz]=foobar) 14 | # printf "Assoc Array\n" 15 | # printarr "assoc_array" 16 | # #Output 17 | # Array 18 | # 0 = foo 19 | # 1 = bar 20 | # 2 = baz 21 | # Assoc Array 22 | # baz = foobar 23 | # foo = bar 24 | # 25 | # @arg $1 string variable name of the array. 26 | # 27 | # @stdout Formatted key value of array. 28 | debug::print_array() { 29 | declare -n __arr="$1" 30 | for k in "${!__arr[@]}"; do printf "%s = %s\n" "$k" "${__arr[$k]}"; done 31 | } 32 | 33 | # @description Function to print ansi escape sequence as is. 34 | # This function helps debug ansi escape sequence in text by displaying the escape codes. 35 | # 36 | # @example 37 | # txt="$(tput bold)$(tput setaf 9)This is bold red text$(tput sgr0).$(tput setaf 10)This is green text$(tput sgr0)" 38 | # debug::print_ansi "$txt" 39 | # #Output 40 | # \e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text\e(B\e[m 41 | # 42 | # @arg $1 string input with ansi escape sequence. 43 | # 44 | # @stdout Ansi escape sequence printed in output as is. 45 | debug::print_ansi() { 46 | #echo $(tr -dc '[:print:]'<<<$1) 47 | printf "%s\n" "${1//$'\e'/\\e}" 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/file.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file File 4 | # @brief Functions for handling files. 5 | 6 | # @description Create temporary file. 7 | # Function creates temporary file with random name. The temporary file will be deleted when script finishes. 8 | # 9 | # @example 10 | # echo "$(file::make_temp_file)" 11 | # #Output 12 | # tmp.vgftzy 13 | # 14 | # @noargs 15 | # 16 | # @exitcode 0 If successful. 17 | # @exitcode 1 If failed to create temp file. 18 | # 19 | # @stdout file name of temporary file created. 20 | file::make_temp_file() { 21 | declare temp_file 22 | type -p mktemp &> /dev/null && { temp_file="$(mktemp -u)" || temp_file="${PWD}/$((RANDOM * 2)).LOG"; } 23 | trap 'rm -f "${temp_file}"' EXIT 24 | printf "%s" "${temp_file}" 25 | } 26 | 27 | # @description Create temporary directory. 28 | # Function creates temporary directory with random name. The temporary directory will be deleted when script finishes. 29 | # 30 | # @example 31 | # echo "$(utility::make_temp_dir)" 32 | # #Output 33 | # tmp.rtfsxy 34 | # 35 | # @arg $1 string Temporary directory prefix 36 | # @arg $2 string Flag to auto remove directory on exit trap (true) 37 | # 38 | # @exitcode 0 If successful. 39 | # @exitcode 1 If failed to create temp directory. 40 | # @exitcode 2 Missing arguments. 41 | # 42 | # @stdout directory name of temporary directory created. 43 | file::make_temp_dir() { 44 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 45 | declare temp_dir prefix="${1}" trap_rm="${2}" 46 | temp_dir=$(mktemp -d 2>/dev/null || mktemp -d -t "${prefix}") 47 | if [[ -n "${trap_rm}" ]]; then 48 | trap 'rm -rf "${temp_dir}"' EXIT 49 | fi 50 | printf "%s" "${temp_dir}" 51 | } 52 | 53 | # @description Get only the filename from string path. 54 | # 55 | # @example 56 | # echo "$(file::name "/path/to/test.md")" 57 | # #Output 58 | # test.md 59 | # 60 | # @arg $1 string path. 61 | # 62 | # @exitcode 0 If successful. 63 | # @exitcode 2 Function missing arguments. 64 | # 65 | # @stdout name of the file with extension. 66 | file::name() { 67 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 68 | printf "%s" "${1##*/}" 69 | } 70 | 71 | # @description Get the basename of file from file name. 72 | # 73 | # @example 74 | # echo "$(file::basename "/path/to/test.md")" 75 | # #Output 76 | # test 77 | # 78 | # @arg $1 string path. 79 | # 80 | # @exitcode 0 If successful. 81 | # @exitcode 2 Function missing arguments. 82 | # 83 | # @stdout basename of the file. 84 | file::basename() { 85 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 86 | 87 | declare file basename 88 | file="${1##*/}" 89 | basename="${file%.*}" 90 | 91 | printf "%s" "${basename}" 92 | } 93 | 94 | # @description Get the extension of file from file name. 95 | # 96 | # @example 97 | # echo "$(file::extension "/path/to/test.md")" 98 | # #Output 99 | # md 100 | # 101 | # @arg $1 string path. 102 | # 103 | # @exitcode 0 If successful. 104 | # @exitcode 1 If no extension is found in the filename. 105 | # @exitcode 2 Function missing arguments. 106 | # 107 | # @stdout extension of the file. 108 | file::extension() { 109 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 110 | declare file extension 111 | file="${1##*/}" 112 | extension="${file##*.}" 113 | [[ "${file}" = "${extension}" ]] && return 1 114 | 115 | printf "%s" "${extension}" 116 | } 117 | 118 | # @description Get directory name from file path. 119 | # 120 | # @example 121 | # echo "$(file::dirname "/path/to/test.md")" 122 | # #Output 123 | # /path/to 124 | # 125 | # @arg $1 string path. 126 | # 127 | # @exitcode 0 If successful. 128 | # @exitcode 2 Function missing arguments. 129 | # 130 | # @stdout directory path. 131 | file::dirname() { 132 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 133 | 134 | declare tmp=${1:-.} 135 | 136 | [[ ${tmp} != *[!/]* ]] && { printf '/\n' && return; } 137 | tmp="${tmp%%"${tmp##*[!/]}"}" 138 | 139 | [[ ${tmp} != */* ]] && { printf '.\n' && return; } 140 | tmp=${tmp%/*} && tmp="${tmp%%"${tmp##*[!/]}"}" 141 | 142 | printf '%s' "${tmp:-/}" 143 | } 144 | 145 | # @description Get absolute path of file or directory. 146 | # 147 | # @example 148 | # file::full_path "../path/to/file.md" 149 | # #Output 150 | # /home/labbots/docs/path/to/file.md 151 | # 152 | # @arg $1 string relative or absolute path to file/direcotry. 153 | # 154 | # @exitcode 0 If successful. 155 | # @exitcode 1 If file/directory does not exist. 156 | # @exitcode 2 Function missing arguments. 157 | # 158 | # @stdout Absolute path to file/directory. 159 | file::full_path() { 160 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 161 | declare input="${1}" 162 | if [[ -f ${input} ]]; then 163 | printf "%s/%s\n" "$(cd "$(file::dirname "${input}")" && pwd)" "${input##*/}" 164 | elif [[ -d ${input} ]]; then 165 | printf "%s\n" "$(cd "${input}" && pwd)" 166 | else 167 | return 1 168 | fi 169 | } 170 | 171 | # @description Get mime type of provided input. 172 | # 173 | # @example 174 | # file::mime_type "../src/file.sh" 175 | # #Output 176 | # application/x-shellscript 177 | # 178 | # @arg $1 string relative or absolute path to file/directory. 179 | # 180 | # @exitcode 0 If successful. 181 | # @exitcode 1 If file/directory does not exist. 182 | # @exitcode 2 Function missing arguments. 183 | # @exitcode 3 If file or mimetype command not found in system. 184 | # 185 | # @stdout mime type of file/directory. 186 | file::mime_type() { 187 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 188 | declare mime_type 189 | if [[ -f "${1}" ]] || [[ -d "${1}" ]]; then 190 | if type -p mimetype &> /dev/null; then 191 | mime_type=$(mimetype --output-format %m "${1}") 192 | elif type -p file &> /dev/null; then 193 | mime_type=$(file --brief --mime-type "${1}") 194 | else 195 | return 3 196 | fi 197 | else 198 | return 1 199 | fi 200 | printf "%s" "${mime_type}" 201 | } 202 | 203 | # @description Search if a given pattern is found in file. 204 | # 205 | # @example 206 | # file::contains_text "./file.sh" "^[ @[:alpha:]]*" 207 | # file::contains_text "./file.sh" "@file" 208 | # #Output 209 | # 0 210 | # 211 | # @arg $1 string relative or absolute path to file/directory. 212 | # @arg $2 string search key or regular expression. 213 | # 214 | # @exitcode 0 If given search parameter is found in file. 215 | # @exitcode 1 If search paramter not found in file. 216 | # @exitcode 2 Function missing arguments. 217 | file::contains_text() { 218 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1 219 | declare -r file="$1" 220 | declare -r text="$2" 221 | grep -q "$text" "$file" 222 | } 223 | -------------------------------------------------------------------------------- /src/format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Format 4 | # @brief Functions to format provided input. 5 | 6 | # @internal 7 | # @description Initialisation script when the code is sourced. 8 | # 9 | # @noargs 10 | __init(){ 11 | _check_terminal_window_size 12 | } 13 | 14 | # @internal 15 | # @description Checks the terminal window size, if necessary, updates the values of LINES and COLUMNS. 16 | # 17 | # @noargs 18 | _check_terminal_window_size() { 19 | shopt -s checkwinsize && (: && :) 20 | trap 'shopt -s checkwinsize; (:;:)' SIGWINCH 21 | } 22 | # @description Format seconds to human readable format. 23 | # 24 | # @example 25 | # echo "$(format::human_readable_seconds "356786")" 26 | # #Output 27 | # 4 days 3 hours 6 minute(s) and 26 seconds 28 | # 29 | # @arg $1 int number of seconds. 30 | # 31 | # @exitcode 0 If successful. 32 | # @exitcode 2 Function missing arguments. 33 | # 34 | # @stdout formatted time string. 35 | format::human_readable_seconds() { 36 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 37 | 38 | declare T="${1}" 39 | declare DAY="$((T / 60 / 60 / 24))" HR="$((T / 60 / 60 % 24))" MIN="$((T / 60 % 60))" SEC="$((T % 60))" 40 | [[ ${DAY} -gt 0 ]] && printf '%d days ' "${DAY}" 41 | [[ ${HR} -gt 0 ]] && printf '%d hours ' "${HR}" 42 | [[ ${MIN} -gt 0 ]] && printf '%d minute(s) ' "${MIN}" 43 | [[ ${DAY} -gt 0 || ${HR} -gt 0 || ${MIN} -gt 0 ]] && printf 'and ' 44 | printf '%d seconds\n' "${SEC}" 45 | } 46 | 47 | # @description Format bytes to human readable format. 48 | # 49 | # @example 50 | # echo "$(format::bytes_to_human "2250")" 51 | # #Output 52 | # 2.19 KB 53 | # 54 | # @arg $1 int size in bytes. 55 | # 56 | # @exitcode 0 If successful. 57 | # @exitcode 2 Function missing arguments. 58 | # 59 | # @stdout formatted file size string. 60 | format::bytes_to_human() { 61 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 62 | 63 | declare b=${1:-0} d='' s=0 S=(Bytes {K,M,G,T,P,E,Y,Z}B) 64 | while ((b > 1024)); do 65 | d="$(printf ".%02d" $((b % 1024 * 100 / 1024)))" 66 | b=$((b / 1024)) && ((s++)) 67 | done 68 | printf "%s\n" "${b}${d} ${S[${s}]}" 69 | } 70 | 71 | # @description Remove Ansi escape sequences from given text. 72 | # 73 | # @example 74 | # format::strip_ansi "\e[1m\e[91mThis is bold red text\e(B\e[m.\e[92mThis is green text.\e(B\e[m" 75 | # #Output 76 | # This is bold red text.This is green text. 77 | # 78 | # @arg $1 string Input text to be ansi stripped. 79 | # 80 | # @exitcode 0 If successful. 81 | # 82 | # @stdout Ansi stripped text. 83 | format::strip_ansi() { 84 | declare tmp esc tpa re 85 | tmp="${1}" 86 | esc=$(printf "\x1b") 87 | tpa=$(printf "\x28") 88 | re="(.*)${esc}[\[${tpa}][0-9]*;*[mKB](.*)" 89 | while [[ "${tmp}" =~ $re ]]; do 90 | tmp="${BASH_REMATCH[1]}${BASH_REMATCH[2]}" 91 | done 92 | printf "%s" "${tmp}" 93 | } 94 | 95 | # @description Prints the given text to centre of terminal. 96 | # 97 | # @example 98 | # format::text_center "This text is in centre of the terminal." "-" 99 | # 100 | # @arg $1 string Text to be printed. 101 | # @arg $2 string Filler symbol to be added to prefix and suffix of the text (optional). Defaults to space as filler. 102 | # 103 | # @exitcode 0 If successful. 104 | # @exitcode 2 Function missing arguments. 105 | # 106 | # @stdout formatted text. 107 | format::text_center() { 108 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1 109 | 110 | declare input="${1}" symbol="${2:- }" filler out no_ansi_out 111 | no_ansi_out=$(format::strip_ansi "$input") 112 | declare -i str_len=${#no_ansi_out} 113 | declare -i filler_len="$(((COLUMNS - str_len) / 2))" 114 | 115 | [[ -n "${symbol}" ]] && symbol="${symbol:0:1}" 116 | for ((i = 0; i < filler_len; i++)); do 117 | filler+="${symbol}" 118 | done 119 | 120 | out="${filler}${input}${filler}" 121 | [[ $(((COLUMNS - str_len) % 2)) -ne 0 ]] && out+="${symbol}" 122 | printf "%s" "${out}" 123 | } 124 | 125 | # @description Format String to print beautiful report. 126 | # 127 | # @example 128 | # format::report "Initialising mission state" "Success" 129 | # #Output 130 | # Initialising mission state ....................................................................[ Success ] 131 | # 132 | # @arg $1 string Text to be printed on the left. 133 | # @arg $2 string Text to be printed within the square brackets. 134 | # 135 | # @exitcode 0 If successful. 136 | # @exitcode 2 Function missing arguments. 137 | # 138 | # @stdout formatted text. 139 | format::report() { 140 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1 141 | 142 | declare symbol="." to_print y hl hlout out 143 | declare input1="${1} " input2="${2}" 144 | input2="[ $input2 ]" 145 | to_print="$((COLUMNS * 60 / 100))" 146 | y=$(( to_print - ( ${#input1} + ${#input2} ) )) 147 | hl="$(printf '%*s' $y '')" 148 | hlout=${hl// /${symbol}} 149 | out="${input1}${hlout}${input2}" 150 | printf "%s\n" "${out}" 151 | } 152 | 153 | # @description Trim given text to width of the terminal window. 154 | # 155 | # @example 156 | # 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." 157 | # #Output 158 | # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod..This is part of second sentence. 159 | # 160 | # @arg $1 string Text of first sentence. 161 | # @arg $2 string Text of second sentence (optional). 162 | # 163 | # @exitcode 0 If successful. 164 | # @exitcode 2 Function missing arguments. 165 | # 166 | # @stdout trimmed text. 167 | format::trim_text_to_term() { 168 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 1 169 | 170 | declare to_print out input1="$1" input2="$2" 171 | if [[ $# = 1 ]]; then 172 | to_print="$((COLUMNS * 93 / 100))" 173 | { [[ ${#input1} -gt ${to_print} ]] && out="${input1:0:to_print}.."; } || { out="$input1"; } 174 | else 175 | to_print="$((COLUMNS * 40 / 100))" 176 | { [[ ${#input1} -gt ${to_print} ]] && out+=" ${input1:0:to_print}.."; } || { out+=" $input1"; } 177 | to_print="$((COLUMNS * 53 / 100))" 178 | { [[ ${#input2} -gt ${to_print} ]] && out+="${input2:0:to_print}.. "; } || { out+="$input2 "; } 179 | fi 180 | printf "%s" "$out" 181 | } 182 | 183 | __init 184 | -------------------------------------------------------------------------------- /src/interaction.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Interaction 4 | # @brief Functions to enable interaction with the user. 5 | 6 | # @description Prompt yes or no question to the user. 7 | # 8 | # @example 9 | # interaction::prompt_yes_no "Are you sure to proceed" "yes" 10 | # #Output 11 | # Are you sure to proceed (y/n)? [y] 12 | # 13 | # @arg $1 string The question to be prompted to the user. 14 | # @arg $2 string default answer \[yes/no\] (optional). 15 | # 16 | # @exitcode 0 If user responds with yes. 17 | # @exitcode 1 If user responds with no. 18 | # @exitcode 2 Function missing arguments. 19 | interaction::prompt_yes_no() { 20 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 21 | declare def_arg response 22 | def_arg="" 23 | response="" 24 | 25 | case "${2}" in 26 | [yY] | [yY][eE][sS]) 27 | def_arg=y 28 | ;; 29 | [nN] | [nN][oO]) 30 | def_arg=n 31 | ;; 32 | esac 33 | 34 | while :; do 35 | printf "%s (y/n)? " "${1}" 36 | [[ -n "${def_arg}" ]] && printf "[%s] " "${def_arg}" 37 | 38 | read -r response 39 | [[ -z "${response}" ]] && response="${def_arg}" 40 | 41 | case "${response}" in 42 | [yY] | [yY][eE][sS]) 43 | response=y 44 | break 45 | ;; 46 | [nN] | [nN][oO]) 47 | response=n 48 | break 49 | ;; 50 | *) 51 | response="" 52 | ;; 53 | esac 54 | done 55 | 56 | [[ "${response}" = 'y' ]] && return 0 || return 1 57 | } 58 | 59 | # @description Prompt question to the user. 60 | # 61 | # @example 62 | # interaction::prompt_response "Choose directory to install" "/home/path" 63 | # #Output 64 | # Choose directory to install? [/home/path] 65 | # 66 | # @arg $1 string The question to be prompted to the user. 67 | # @arg $2 string default answer (optional). 68 | # 69 | # @exitcode 0 If user responds with answer. 70 | # @exitcode 2 Function missing arguments. 71 | # 72 | # @stdout User entered answer to the question. 73 | interaction::prompt_response() { 74 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 75 | 76 | declare def_arg response 77 | response="" 78 | def_arg="${2}" 79 | 80 | while :; do 81 | printf "%s ? " "${1}" 82 | [[ -n "${def_arg}" ]] && [[ "${def_arg}" != "-" ]] && printf "[%s] " "${def_arg}" 83 | 84 | read -r response 85 | [[ -n "${response}" ]] && break 86 | 87 | if [[ -z "${response}" ]] && [[ -n "${def_arg}" ]]; then 88 | response="${def_arg}" 89 | break 90 | fi 91 | done 92 | 93 | [[ "${response}" = "-" ]] && response="" 94 | 95 | printf "%s" "${response}" 96 | } 97 | -------------------------------------------------------------------------------- /src/json.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Json 4 | # @brief Simple json manipulation. These functions does not completely replace `jq` in any way. 5 | 6 | # @description Extract value from json based on key and position. 7 | # Input to the function can be a pipe output, here-string or file. 8 | # @example 9 | # json::get_value "id" "1" < json_file 10 | # json::get_value "id" <<< "${json_var}" 11 | # echo "{\"data\":{\"id\":\"123\",\"value\":\"name string\"}}" | json::get_value "id" 12 | # 13 | # @arg $1 string id of the field to fetch. 14 | # @arg $2 int position of value to extract.Defaults to 1.(optional) 15 | # 16 | # @exitcode 0 If match successful. 17 | # @exitcode 2 Function missing arguments. 18 | # 19 | # @stdout string value of extracted key. 20 | json::get_value() { 21 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 22 | 23 | declare LC_ALL=C num="${2:-1}" 24 | grep -o "\"""${1}""\"\:.*" | sed -e "s/.*\"""${1}""\": //" -e 's/[",]*$//' -e 's/["]*$//' -e 's/[,]*$//' -e "s/\"//" -n -e "${num}"p 25 | } 26 | -------------------------------------------------------------------------------- /src/misc.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Miscellaneous 4 | # @brief Set of miscellaneous helper functions. 5 | 6 | # @internal 7 | # @description Check if script is run in terminal. 8 | # 9 | # @noargs 10 | # 11 | # @exitcode 0 If script is run on terminal. 12 | # @exitcode 1 If script is not run on terminal. 13 | _is_terminal() { 14 | [[ -t 1 || -z ${TERM} ]] && return 0 || return 1 15 | } 16 | 17 | # @description Check if internet connection is available. 18 | # 19 | # @example 20 | # misc::check_internet_connection 21 | # 22 | # @noargs 23 | # 24 | # @exitcode 0 If script can connect to internet. 25 | # @exitcode 1 If script cannot access internet. 26 | misc::check_internet_connection() { 27 | declare check_internet 28 | if _is_terminal; then 29 | check_internet="$(sh -ic 'exec 3>&1 2>/dev/null; { curl --compressed -Is google.com 1>&3; kill 0; } | { sleep 10; kill 0; }' || :)" 30 | else 31 | check_internet="$(curl --compressed -Is google.com -m 10)" 32 | fi 33 | if [[ -z ${check_internet} ]]; then 34 | return 1 35 | fi 36 | } 37 | 38 | # @description Get list of process ids based on process name. 39 | # 40 | # @example 41 | # misc::get_pid "chrome" 42 | # #Ouput 43 | # 25951 44 | # 26043 45 | # 26528 46 | # 26561 47 | # 48 | # @arg $1 Name of the process to search. 49 | # 50 | # @exitcode 0 If match successful. 51 | # @exitcode 2 Function missing arguments. 52 | # 53 | # @stdout list of process ids. 54 | misc::get_pid() { 55 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 56 | 57 | pgrep "${1}" 58 | } 59 | 60 | # @description Get user id based on username. 61 | # 62 | # @example 63 | # misc::get_uid "labbots" 64 | # #Ouput 65 | # 1000 66 | # 67 | # @arg $1 username to search. 68 | # 69 | # @exitcode 0 If match successful. 70 | # @exitcode 2 Function missing arguments. 71 | # 72 | # @stdout string uid for the username. 73 | misc::get_uid() { 74 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 75 | 76 | user_id=$(id "${1}" 2> /dev/null) 77 | declare -i ret=$? 78 | if [[ $ret -ne 0 ]]; then 79 | printf "No user found with username: %s" "${1}\n" 80 | return 1 81 | fi 82 | 83 | printf "%s\n" "${user_id}" | sed -e 's/(.*$//' -e 's/^uid=//' 84 | 85 | unset user_id 86 | } 87 | 88 | # @description Generate random uuid. 89 | # 90 | # @example 91 | # misc::generate_uuid 92 | # #Ouput 93 | # 65bc64d1-d355-4ffc-a9d9-dc4f3954c34c 94 | # 95 | # @noargs 96 | # 97 | # @exitcode 0 If match successful. 98 | # 99 | # @stdout random generated uuid. 100 | misc::generate_uuid() { 101 | C="89ab" 102 | 103 | for ((N=0;N<16;++N)); do 104 | B="$((RANDOM%256))" 105 | 106 | case "$N" in 107 | 6) printf '4%x' "$((B%16))" ;; 108 | 8) printf '%c%x' "${C:$RANDOM%${#C}:1}" "$((B%16))" ;; 109 | 110 | 3|5|7|9) 111 | printf '%02x-' "$B" 112 | ;; 113 | 114 | *) 115 | printf '%02x' "$B" 116 | ;; 117 | esac 118 | done 119 | 120 | printf '\n' 121 | } 122 | -------------------------------------------------------------------------------- /src/os.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Operating System 4 | # @brief Functions to detect Operating system and version. 5 | 6 | # @description Identify the OS the function is run on. 7 | # 8 | # @noargs 9 | # 10 | # @example 11 | # os::detect_os 12 | # #Output 13 | # linux 14 | # 15 | # @exitcode 0 If OS is successfully detected. 16 | # @exitcode 1 If unable to detect OS. 17 | # 18 | # @stdout Operating system name (linux, mac or windows). 19 | os::detect_os() { 20 | declare uname os 21 | uname=$(command -v uname) 22 | 23 | case $("${uname}" | tr '[:upper:]' '[:lower:]') in 24 | linux*) 25 | os="linux" 26 | ;; 27 | darwin*) 28 | os="mac" 29 | ;; 30 | msys* | cygwin* | mingw* | nt | win*) 31 | # or possible 'bash on windows' 32 | os="windows" 33 | ;; 34 | *) 35 | return 1 36 | ;; 37 | esac 38 | printf "%s" "${os}" 39 | } 40 | 41 | # @description Identify the distribution flavour of linux. 42 | # 43 | # @noargs 44 | # 45 | # @example 46 | # os::detect_linux_distro 47 | # #Output 48 | # ubuntu 49 | # @exitcode 0 If Linux distro is successfully detected. 50 | # @exitcode 1 If unable to detect OS distro. 51 | # 52 | # @stdout Linux OS distribution name (ubuntu, debian, suse, etc.,). 53 | os::detect_linux_distro() { 54 | declare distro 55 | if [[ -f /etc/os-release ]]; then 56 | # shellcheck disable=SC1091 57 | . "/etc/os-release" 58 | distro="${NAME}" 59 | elif type lsb_release >/dev/null 2>&1; then 60 | # linuxbase.org 61 | distro=$(lsb_release -si) 62 | elif [[ -f /etc/lsb-release ]]; then 63 | # For some versions of Debian/Ubuntu without lsb_release command 64 | # shellcheck disable=SC1091 65 | . /etc/lsb-release 66 | distro="${DISTRIB_ID}" 67 | elif [[ -f /etc/debian_version ]]; then 68 | # Older Debian/Ubuntu/etc. 69 | distro="debian" 70 | elif [[ -f /etc/SuSe-release ]]; then 71 | # Older SuSE/etc. 72 | distro="suse" 73 | elif [[ -f /etc/redhat-release ]]; then 74 | # Older Red Hat, CentOS, etc. 75 | distro="redhat" 76 | else 77 | return 1 78 | fi 79 | printf "%s" "${distro}" | tr '[:upper:]' '[:lower:]' 80 | } 81 | 82 | # @description Identify the Linux version. 83 | # 84 | # @noargs 85 | # 86 | # @example 87 | # os::detect_linux_version 88 | # #Output 89 | # 20.04 90 | # 91 | # @exitcode 0 If Linux version is successfully detected. 92 | # @exitcode 1 If unable to detect Linux version. 93 | # 94 | # @stdout Linux OS version number (18.04, 20.04, etc.,). 95 | os::detect_linux_version() { 96 | declare distro_version 97 | if [[ -f /etc/os-release ]]; then 98 | # shellcheck disable=SC1091 99 | . "/etc/os-release" 100 | distro_version="${VERSION_ID}" 101 | elif type lsb_release >/dev/null 2>&1; then 102 | # linuxbase.org 103 | distro_version=$(lsb_release -sr) 104 | elif [[ -f /etc/lsb-release ]]; then 105 | # For some versions of Debian/Ubuntu without lsb_release command 106 | # shellcheck disable=SC1091 107 | . /etc/lsb-release 108 | distro_version="${DISTRIB_RELEASE}" 109 | else 110 | return 1 111 | fi 112 | printf "%s" "${distro_version}" 113 | } 114 | 115 | # @description Identify the MacOS version. 116 | # 117 | # @noargs 118 | # 119 | # @example 120 | # os::detect_linux_version 121 | # #Output 122 | # 10.15.7 123 | # @exitcode 0 If MacOS version is successfully detected. 124 | # @exitcode 1 If unable to detect MacOS version. 125 | # 126 | # @stdout MacOS version number (10.15.6, etc.,) 127 | os::detect_mac_version() { 128 | if [[ "$(os::detect_os)" = "mac" ]]; then 129 | declare mac_version 130 | mac_version="$(sw_vers -productVersion)" 131 | printf "%s" "${mac_version}" 132 | else 133 | return 1 134 | fi 135 | } 136 | -------------------------------------------------------------------------------- /src/string.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file String 4 | # @brief Functions for string operations and manipulations. 5 | 6 | # @description Strip whitespace from the beginning and end of a string. 7 | # 8 | # @example 9 | # echo "$(string::trim " Hello World! ")" 10 | # #Output 11 | # Hello World! 12 | # 13 | # @arg $1 string The string to be trimmed. 14 | # 15 | # @exitcode 0 If successful. 16 | # @exitcode 2 Function missing arguments. 17 | # 18 | # @stdout The trimmed string. 19 | string::trim() { 20 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 21 | 22 | : "${1#"${1%%[![:space:]]*}"}" 23 | : "${_%"${_##*[![:space:]]}"}" 24 | printf '%s\n' "$_" 25 | } 26 | 27 | # @description Split a string to array by a delimiter. 28 | # 29 | # @example 30 | # array=( $(string::split "a,b,c" ",") ) 31 | # printf "%s" "$(string::split "Hello!World" "!")" 32 | # #Output 33 | # Hello 34 | # World 35 | # 36 | # @arg $1 string The input string. 37 | # @arg $2 string The delimiter string. 38 | # 39 | # @exitcode 0 If successful. 40 | # @exitcode 2 Function missing arguments. 41 | # 42 | # @stdout Returns an array of strings created by splitting the string parameter by the delimiter. 43 | string::split() { 44 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 45 | declare -a arr=() 46 | IFS=$'\n' read -d "" -ra arr <<< "${1//$2/$'\n'}" 47 | printf '%s\n' "${arr[@]}" 48 | } 49 | 50 | # @description Strip characters from the beginning of a string. 51 | # 52 | # @example 53 | # echo "$(string::lstrip "Hello World!" "He")" 54 | # #Output 55 | # llo World! 56 | # 57 | # @arg $1 string The input string. 58 | # @arg $2 string The characters you want to strip. 59 | # 60 | # @exitcode 0 If successful. 61 | # @exitcode 2 Function missing arguments. 62 | # 63 | # @stdout Returns the modified string. 64 | string::lstrip() { 65 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 66 | printf '%s\n' "${1##$2}" 67 | } 68 | 69 | # @description Strip characters from the end of a string. 70 | # 71 | # @example 72 | # echo "$(string::rstrip "Hello World!" "d!")" 73 | # #Output 74 | # Hello Worl 75 | # 76 | # @arg $1 string The input string. 77 | # @arg $2 string The characters you want to strip. 78 | # 79 | # @exitcode 0 If successful. 80 | # @exitcode 2 Function missing arguments. 81 | # 82 | # @stdout Returns the modified string. 83 | string::rstrip() { 84 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 85 | printf '%s\n' "${1%%$2}" 86 | } 87 | 88 | # @description Make a string lowercase. 89 | # 90 | # @example 91 | # echo "$(string::to_lower "HellO")" 92 | # #Output 93 | # hello 94 | # 95 | # @arg $1 string The input string. 96 | # 97 | # @exitcode 0 If successful. 98 | # @exitcode 2 Function missing arguments. 99 | # 100 | # @stdout Returns the lowercased string. 101 | string::to_lower() { 102 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 103 | if [[ ${BASH_VERSINFO:-0} -ge 4 ]]; then 104 | printf '%s\n' "${1,,}" 105 | else 106 | printf "%s\n" "${@}" | tr '[:upper:]' '[:lower:]' 107 | fi 108 | } 109 | 110 | # @description Make a string all uppercase. 111 | # 112 | # @example 113 | # echo "$(string::to_upper "HellO")" 114 | # #Output 115 | # HELLO 116 | # 117 | # @arg $1 string The input string. 118 | # 119 | # @exitcode 0 If successful. 120 | # @exitcode 2 Function missing arguments. 121 | # 122 | # @stdout Returns the uppercased string. 123 | string::to_upper() { 124 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 125 | if [[ ${BASH_VERSINFO:-0} -ge 4 ]]; then 126 | printf '%s\n' "${1^^}" 127 | else 128 | printf "%s\n" "${@}" | tr '[:lower:]' '[:upper:]' 129 | fi 130 | } 131 | 132 | # @description Check whether the search string exists within the input string. 133 | # 134 | # @example 135 | # string::contains "Hello World!" "lo" 136 | # 137 | # @arg $1 string The input string. 138 | # @arg $2 string The search key. 139 | # @exitcode 0 If match found. 140 | # @exitcode 1 If no match found. 141 | # @exitcode 2 Function missing arguments. 142 | string::contains() { 143 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 144 | # Usage: string_contains hello he 145 | [[ "${1}" == *${2}* ]] 146 | } 147 | 148 | # @description Check whether the input string starts with key string. 149 | # 150 | # @example 151 | # string::starts_with "Hello World!" "He" 152 | # 153 | # @arg $1 string The input string. 154 | # @arg $2 string The search key. 155 | # @exitcode 0 If match found. 156 | # @exitcode 1 If no match found. 157 | # @exitcode 2 Function missing arguments. 158 | string::starts_with() { 159 | # Usage: string_starts_with hello he 160 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 161 | [[ "${1}" == ${2}* ]] 162 | } 163 | 164 | # @description Check whether the input string ends with key string. 165 | # 166 | # @example 167 | # string::ends_with "Hello World!" "d!" 168 | # 169 | # @arg $1 string The input string. 170 | # @arg $2 string The search key. 171 | # @exitcode 0 If match found. 172 | # @exitcode 1 If no match found. 173 | # @exitcode 2 Function missing arguments. 174 | string::ends_with() { 175 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 176 | # Usage: string_ends_wit hello lo 177 | [[ "${1}" == *${2} ]] 178 | } 179 | 180 | # @description Check whether the input string matches the given regex. 181 | # 182 | # @example 183 | # string::regex "HELLO" "^[A-Z]*$" 184 | # 185 | # @arg $1 string The input string. 186 | # @arg $2 string The search key. 187 | # @exitcode 0 If match found. 188 | # @exitcode 1 If no match found. 189 | # @exitcode 2 Function missing arguments. 190 | string::regex() { 191 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 192 | if [[ ${1} =~ ${2} ]]; then 193 | return 0 194 | else 195 | return 1 196 | fi 197 | 198 | } 199 | -------------------------------------------------------------------------------- /src/terminal.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Terminal 4 | # @brief Set of useful terminal functions. 5 | 6 | # @description Check if script is run in terminal. 7 | # 8 | # @noargs 9 | # 10 | # @exitcode 0 If script is run on terminal. 11 | # @exitcode 1 If script is not run on terminal. 12 | terminal::is_term() { 13 | [[ -t 1 || -z ${TERM} ]] && return 0 || return 1 14 | } 15 | 16 | # @description Detect profile rc file for zsh and bash of current script running user. 17 | # 18 | # @noargs 19 | # 20 | # @exitcode 0 If script is run on terminal. 21 | # @exitcode 1 If script is not run on terminal. 22 | # 23 | # @stdout path to the profile file. 24 | terminal::detect_profile() { 25 | declare CURRENT_SHELL="${SHELL##*/}" 26 | case "${CURRENT_SHELL}" in 27 | 'bash') DETECTED_PROFILE="${HOME}/.bashrc" ;; 28 | 'zsh') DETECTED_PROFILE="${HOME}/.zshrc" ;; 29 | *) if [[ -f "${HOME}/.profile" ]]; then 30 | DETECTED_PROFILE="${HOME}/.profile" 31 | else 32 | printf "No compaitable shell file\n" && exit 1 33 | fi ;; 34 | esac 35 | printf "%s\n" "${DETECTED_PROFILE}" 36 | } 37 | 38 | # @description Clear the output in terminal on the specified line number. 39 | # This function clears line only on terminal. 40 | # 41 | # @arg $1 Line number to clear. Defaults to 1. (optional) 42 | # 43 | # @exitcode 0 If script is run on terminal. 44 | # 45 | # @stdout clear line ansi code. 46 | terminal::clear_line() { 47 | if terminal::is_term; then 48 | declare line=${1:-1} 49 | printf "\033[%sA\033[2K" "${line}" 50 | fi 51 | } 52 | -------------------------------------------------------------------------------- /src/validation.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Validation 4 | # @brief Functions to perform validation on given data. 5 | 6 | # @description Validate whether a given input is a valid email address or not. 7 | # 8 | # @example 9 | # test='test@gmail.com' 10 | # validation::email "${test}" 11 | # echo $? 12 | # #Output 13 | # 0 14 | # 15 | # @arg $1 string input email address to validate. 16 | # 17 | # @exitcode 0 If provided input is an email address. 18 | # @exitcode 1 If provided input is not an email address. 19 | # @exitcode 2 Function missing arguments. 20 | validation::email() { 21 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 22 | declare email_re 23 | email_re="^([A-Za-z]+[A-Za-z0-9]*\+?((\.|\-|\_)?[A-Za-z]+[A-Za-z0-9]*)*)@(([A-Za-z0-9]+)+((\.|\-|\_)?([A-Za-z0-9]+)+)*)+\.([A-Za-z]{2,})+$" 24 | [[ "${1}" =~ ${email_re} ]] && return 0 || return 1 25 | } 26 | 27 | # @description Validate whether a given input is a valid IP V4 address. 28 | # 29 | # @example 30 | # ips=' 31 | # 4.2.2.2 32 | # a.b.c.d 33 | # 192.168.1.1 34 | # 0.0.0.0 35 | # 255.255.255.255 36 | # 255.255.255.256 37 | # 192.168.0.1 38 | # 192.168.0 39 | # 1234.123.123.123 40 | # 0.192.168.1 41 | # ' 42 | # for ip in $ips; do 43 | # if validation::ipv4 $ip; then stat='good'; else stat='bad'; fi 44 | # printf "%-20s: %s\n" "$ip" "$stat" 45 | # done 46 | # #Output 47 | # 4.2.2.2 : good 48 | # a.b.c.d : bad 49 | # 192.168.1.1 : good 50 | # 0.0.0.0 : good 51 | # 255.255.255.255 : good 52 | # 255.255.255.256 : bad 53 | # 192.168.0.1 : good 54 | # 192.168.0 : bad 55 | # 1234.123.123.123 : bad 56 | # 0.192.168.1 : good 57 | # 58 | # @arg $1 string input IPv4 address. 59 | # 60 | # @exitcode 0 If provided input is a valid IPv4. 61 | # @exitcode 1 If provided input is not a valid IPv4. 62 | # @exitcode 2 Function missing arguments. 63 | validation::ipv4() { 64 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 65 | declare ip="${1}" 66 | declare IFS=. 67 | # shellcheck disable=SC2206 68 | declare -a a=($ip) 69 | [[ "${ip}" =~ ^[0-9]+(\.[0-9]+){3}$ ]] || return 1 70 | # Test values of quads 71 | declare quad 72 | for quad in {0..3}; do 73 | [[ "${a[$quad]}" -gt 255 ]] && return 1 74 | done 75 | return 0 76 | } 77 | 78 | # @description Validate whether a given input is a valid IP V6 address. 79 | # 80 | # @example 81 | # ips=' 82 | # 2001:db8:85a3:8d3:1319:8a2e:370:7348 83 | # fe80::1ff:fe23:4567:890a 84 | # fe80::1ff:fe23:4567:890a%eth2 85 | # 2001:0db8:85a3:0000:0000:8a2e:0370:7334:foo:bar 86 | # fezy::1ff:fe23:4567:890a 87 | # :: 88 | # 2001:db8:: 89 | # ' 90 | # for ip in $ips; do 91 | # if validation::ipv6 $ip; then stat='good'; else stat='bad'; fi 92 | # printf "%-50s= %s\n" "$ip" "$stat" 93 | # done 94 | # #Output 95 | # 2001:db8:85a3:8d3:1319:8a2e:370:7348 = good 96 | # fe80::1ff:fe23:4567:890a = good 97 | # fe80::1ff:fe23:4567:890a%eth2 = good 98 | # 2001:0db8:85a3:0000:0000:8a2e:0370:7334:foo:bar = bad 99 | # fezy::1ff:fe23:4567:890a = bad 100 | # :: = good 101 | # 2001:db8:: = good 102 | # 103 | # @arg $1 string input IPv6 address. 104 | # 105 | # @exitcode 0 If provided input is a valid IPv6. 106 | # @exitcode 1 If provided input is not a valid IPv6. 107 | # @exitcode 2 Function missing arguments. 108 | validation::ipv6() { 109 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 110 | 111 | declare ip="${1}" 112 | declare re="^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|\ 113 | ([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|\ 114 | ([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|\ 115 | ([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|\ 116 | :((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|\ 117 | ::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|\ 118 | (2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|\ 119 | (2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$" 120 | 121 | [[ "${ip}" =~ $re ]] && return 0 || return 1 122 | } 123 | 124 | # @description Validate if given variable is entirely alphabetic characters. 125 | # 126 | # @example 127 | # test='abcABC' 128 | # validation::alpha "${test}" 129 | # echo $? 130 | # #Output 131 | # 0 132 | # 133 | # @arg $1 string Value of variable to validate. 134 | # 135 | # @exitcode 0 If input is only alpha characters. 136 | # @exitcode 1 If input contains any non alpha characters. 137 | # @exitcode 2 Function missing arguments. 138 | validation::alpha() { 139 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 140 | 141 | declare re='^[[:alpha:]]+$' 142 | if [[ "${1}" =~ $re ]]; then 143 | return 0 144 | fi 145 | return 1 146 | } 147 | 148 | # @description Check if given variable contains only alpha-numeric characters. 149 | # 150 | # @example 151 | # test='abc123' 152 | # validation::alpha_num "${test}" 153 | # echo $? 154 | # #Output 155 | # 0 156 | # 157 | # @arg $1 string Value of variable to validate. 158 | # 159 | # @exitcode 0 If input is an alpha-numeric. 160 | # @exitcode 1 If input is not an alpha-numeric. 161 | # @exitcode 2 Function missing arguments. 162 | validation::alpha_num() { 163 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 164 | 165 | declare re='^[[:alnum:]]+$' 166 | if [[ "${1}" =~ $re ]]; then 167 | return 0 168 | fi 169 | return 1 170 | } 171 | 172 | # @description Validate if given variable contains only alpha-numeric characters, as well as dashes and underscores. 173 | # 174 | # @example 175 | # test='abc-ABC_cD' 176 | # validation::alpha_dash "${test}" 177 | # echo $? 178 | # #Output 179 | # 0 180 | # 181 | # @arg $1 string Value of variable to validate. 182 | # 183 | # @exitcode 0 If input is valid. 184 | # @exitcode 1 If input the input is not valid. 185 | # @exitcode 2 Function missing arguments. 186 | validation::alpha_dash() { 187 | [[ $# = 0 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 2 188 | 189 | declare re='^[[:alpha:]_-]+$' 190 | if [[ "${1}" =~ $re ]]; then 191 | return 0 192 | fi 193 | return 1 194 | } 195 | 196 | # @description Compares version numbers and provides return based on whether the value in equal, less than or greater. 197 | # 198 | # @arg $1 string Version number to check (eg: 1.0.1) 199 | # $arg $2 string Version number to check (eg: 1.0.1) 200 | # 201 | # @example 202 | # test='abc-ABC_cD' 203 | # validation::version_comparison "12.0.1" "12.0.1" 204 | # echo $? 205 | # #Output 206 | # 0 207 | # 208 | # @exitcode 0 version number is equal. 209 | # @exitcode 1 $1 version number is greater than $2. 210 | # @exitcode 2 $1 version number is less than $2. 211 | # @exitcode 3 Function is missing required arguments. 212 | # @exitcode 4 Provided input argument is in invalid format. 213 | validation::version_comparison() { 214 | [[ $# -lt 2 ]] && printf "%s: Missing arguments\n" "${FUNCNAME[0]}" && return 3 215 | 216 | declare regex="^[.0-9]*$" 217 | ! [[ $1 =~ $regex ]] && printf "Invalid argument: %s \n" "${1}" && return 4 218 | ! [[ $2 =~ $regex ]] && printf "Invalid argument invalid: %s \n" "${2}" && return 4 219 | 220 | if [[ "$1" == "$2" ]]; then 221 | return 0 222 | fi 223 | declare IFS=. 224 | declare -a ver1 ver2 225 | read -r -a ver1 <<<"${1}" 226 | read -r -a ver2 <<<"${2}" 227 | # fill empty fields in ver1 with zeros 228 | for ((i = ${#ver1[@]}; i < ${#ver2[@]}; i++)); do 229 | ver1[i]=0 230 | done 231 | for ((i = 0; i < ${#ver1[@]}; i++)); do 232 | if [[ -z ${ver2[i]} ]]; then 233 | # fill empty fields in ver2 with zeros 234 | ver2[i]=0 235 | fi 236 | if ((10#${ver1[i]} > 10#${ver2[i]})); then 237 | return 1 238 | fi 239 | if ((10#${ver1[i]} < 10#${ver2[i]})); then 240 | return 2 241 | fi 242 | done 243 | return 0 244 | } 245 | -------------------------------------------------------------------------------- /src/variable.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # @file Variable 4 | # @brief Functions for handling variables. 5 | 6 | # @description Check if given variable is array. 7 | # Pass the variable name instead of value of the variable. 8 | # 9 | # @example 10 | # arr=("a" "b" "c") 11 | # variable::is_array "arr" 12 | # #Output 13 | # 0 14 | # 15 | # @arg $1 string name of the variable to check. 16 | # 17 | # @exitcode 0 If input is array. 18 | # @exitcode 1 If input is not an array. 19 | variable::is_array() { 20 | if [[ -z "${1}" ]]; then 21 | return 1 22 | else 23 | declare -p "${1}" 2> /dev/null | grep 'declare \-[aA]' > /dev/null && return 0 24 | fi 25 | return 1 26 | } 27 | 28 | # @description Check if given variable is a number. 29 | # 30 | # @example 31 | # variable::is_numeric "1234" 32 | # #Output 33 | # 0 34 | # 35 | # @arg $1 mixed Value of variable to check. 36 | # 37 | # @exitcode 0 If input is number. 38 | # @exitcode 1 If input is not a number. 39 | variable::is_numeric() { 40 | declare re='^[0-9]+$' 41 | if [[ ${1} =~ $re ]]; then 42 | return 0 43 | fi 44 | return 1 45 | } 46 | 47 | # @description Check if given variable is an integer. 48 | # 49 | # @example 50 | # variable::is_int "+1234" 51 | # #Output 52 | # 0 53 | # 54 | # @arg $1 mixed Value of variable to check. 55 | # 56 | # @exitcode 0 If input is an integer. 57 | # @exitcode 1 If input is not an integer. 58 | variable::is_int() { 59 | declare re='^[+-]?[0-9]+$' 60 | if [[ ${1} =~ $re ]]; then 61 | return 0 62 | fi 63 | return 1 64 | } 65 | 66 | # @description Check if given variable is a float. 67 | # 68 | # @example 69 | # variable::is_float "+1234.0" 70 | # #Output 71 | # 0 72 | # 73 | # @arg $1 mixed Value of variable to check. 74 | # 75 | # @exitcode 0 If input is a float. 76 | # @exitcode 1 If input is not a float. 77 | variable::is_float() { 78 | declare re='^[+-]?[0-9]+.?[0-9]*$' 79 | if [[ ${1} =~ $re ]]; then 80 | return 0 81 | fi 82 | return 1 83 | } 84 | 85 | # @description Check if given variable is a boolean. 86 | # 87 | # @example 88 | # variable::is_bool "true" 89 | # #Output 90 | # 0 91 | # 92 | # @arg $1 mixed Value of variable to check. 93 | # 94 | # @exitcode 0 If input is a boolean. 95 | # @exitcode 1 If input is not a boolean. 96 | variable::is_bool() { 97 | [[ "${1}" = true || "${1}" = false ]] && return 0 || return 1 98 | } 99 | 100 | # @description Check if given variable is a true. 101 | # 102 | # @example 103 | # variable::is_true "true" 104 | # #Output 105 | # 0 106 | # 107 | # @arg $1 mixed Value of variable to check. 108 | # 109 | # @exitcode 0 If input is true. 110 | # @exitcode 1 If input is not true. 111 | variable::is_true() { 112 | [[ "${1}" = true || "${1}" -eq 0 ]] && return 0 || return 1 113 | } 114 | 115 | # @description Check if given variable is false. 116 | # 117 | # @example 118 | # variable::is_false "false" 119 | # #Output 120 | # 0 121 | # 122 | # @arg $1 mixed Value of variable to check. 123 | # 124 | # @exitcode 0 If input is false. 125 | # @exitcode 1 If input is not false. 126 | variable::is_false() { 127 | [[ "${1}" = false || "${1}" -eq 1 ]] && return 0 || return 1 128 | } 129 | 130 | # @description Check if given variable is empty or null. 131 | # 132 | # @example 133 | # test='' 134 | # variable::is_empty_or_null $test 135 | # #Output 136 | # 0 137 | # 138 | # @arg $1 mixed Value of variable to check. 139 | # 140 | # @exitcode 0 If input is empty or null. 141 | # @exitcode 1 If input is not empty or null. 142 | variable::is_empty_or_null() { 143 | [[ -z "${1}" || "${1}" = "null" ]] && return 0 || return 1 144 | } 145 | --------------------------------------------------------------------------------