{"id":20227457,"url":"https://github.com/fkemser/shtemplate","last_synced_at":"2026-05-17T02:39:13.155Z","repository":{"id":244298005,"uuid":"746367454","full_name":"fkemser/SHtemplate","owner":"fkemser","description":"A template repository for POSIX-/Bourne-Shell(sh) projects.","archived":false,"fork":false,"pushed_at":"2024-09-19T21:40:49.000Z","size":5920,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-03T13:14:54.285Z","etag":null,"topics":["bash","posix","sh","shell","template"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fkemser.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-21T20:52:36.000Z","updated_at":"2024-09-19T21:40:53.000Z","dependencies_parsed_at":"2024-06-13T23:01:27.616Z","dependency_job_id":"2ab6a5a1-77fa-4c7b-8e5a-8c0e864283c7","html_url":"https://github.com/fkemser/SHtemplate","commit_stats":null,"previous_names":["fkemser/shtemplate"],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/fkemser/SHtemplate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fkemser%2FSHtemplate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fkemser%2FSHtemplate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fkemser%2FSHtemplate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fkemser%2FSHtemplate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fkemser","download_url":"https://codeload.github.com/fkemser/SHtemplate/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fkemser%2FSHtemplate/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267967720,"owners_count":24173566,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bash","posix","sh","shell","template"],"created_at":"2024-11-14T07:24:50.884Z","updated_at":"2026-05-17T02:39:13.142Z","avatar_url":"https://github.com/fkemser.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- Improved compatibility of back to top link: See: https://github.com/othneildrew/Best-README-Template/pull/73 --\u003e\n\u003ca name=\"readme-top\"\u003e\u003c/a\u003e\n\u003c!--\n*** Thanks for checking out the Best-README-Template. If you have a suggestion\n*** that would make this better, please fork the repo and create a pull request\n*** or simply open an issue with the tag \"enhancement\".\n*** Don't forget to give the project a star!\n*** Thanks again! Now go create something AMAZING! :D\n--\u003e\n\n\n\n\u003c!-- PROJECT SHIELDS --\u003e\n\u003c!--\n*** I'm using markdown \"reference style\" links for readability.\n*** Reference links are enclosed in brackets [ ] instead of parentheses ( ).\n*** See the bottom of this document for the declaration of the reference variables\n*** for contributors-url, forks-url, etc. This is an optional, concise syntax you may use.\n*** https://www.markdownguide.org/basic-syntax/#reference-style-links\n--\u003e\n[![Contributors][contributors-shield]][contributors-url]\n[![Forks][forks-shield]][forks-url]\n[![Stargazers][stars-shield]][stars-url]\n[![Issues][issues-shield]][issues-url]\n[![MIT License][license-shield]][license-url]\n\u003c!-- [![LinkedIn][linkedin-shield]][linkedin-url] --\u003e\n\n\n\n\u003c!-- PROJECT LOGO --\u003e\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003c!-- \u003ca href=\"https://github.com/fkemser/SHtemplate\"\u003e\n    \u003cimg src=\"images/logo.png\" alt=\"Logo\" width=\"80\" height=\"80\"\u003e\n  \u003c/a\u003e --\u003e\n\n\u003ch3 align=\"center\"\u003eSHtemplate\u003c/h3\u003e\n\n  \u003cp align=\"center\"\u003e\n    A template repository for POSIX-/Bourne-Shell(sh) projects.\n    \u003cbr /\u003e\n    \u003ca href=\"https://github.com/fkemser/SHtemplate\"\u003e\u003cstrong\u003eExplore the docs »\u003c/strong\u003e\u003c/a\u003e\n    \u003cbr /\u003e\n    \u003cbr /\u003e\n    \u003ca href=\"https://github.com/fkemser/SHtemplate\"\u003eView Demo\u003c/a\u003e\n    ·\n    \u003ca href=\"https://github.com/fkemser/SHtemplate/issues\"\u003eReport Bug\u003c/a\u003e\n    ·\n    \u003ca href=\"https://github.com/fkemser/SHtemplate/issues\"\u003eRequest Feature\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\n\n\u003c!-- TABLE OF CONTENTS --\u003e\n\u003cdetails\u003e\n  \u003csummary\u003eTable of Contents\u003c/summary\u003e\n  \u003col\u003e\n    \u003cli\u003e\n      \u003ca href=\"#about-the-project\"\u003eAbout The Project\u003c/a\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#built-with\"\u003eBuilt With\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#testing-environment\"\u003eTesting Environment\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\n      \u003ca href=\"#getting-started\"\u003eGetting Started\u003c/a\u003e\n      \u003cul\u003e\n        \u003cli\u003e\n          \u003ca href=\"#prerequisites\"\u003ePrerequisites\u003c/a\u003e\n          \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#debian\"\u003eDebian\u003c/a\u003e\u003c/li\u003e\n          \u003c/ul\u003e\n        \u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#installation\"\u003eInstallation\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#customization\"\u003eCustomization\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\n      \u003ca href=\"#template-structure\"\u003eTemplate Structure\u003c/a\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#overview\"\u003eOverview\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#etcruncfgsh\"\u003e/etc/run.cfg.sh\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#lib\"\u003e/lib/...\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#srcinitsh\"\u003e/src/init.sh\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#srclangrunlangsh-repository-string-constants-files\"\u003e/src/lang/run.\u003c...\u003e.lang.sh (Repository String Constants Files)\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\n      \u003ca href=\"#srcrunsh-repository-run-file\"\u003e/src/run.sh (Repository Run File)\u003c/a\u003e\n      \u003cul\u003e\n        \u003cli\u003e\u003ca href=\"#modes\"\u003eModes\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#actions\"\u003eActions\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#constants\"\u003eConstants\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003ca href=\"#variables\"\u003eVariables\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\n          \u003ca href=\"#functions\"\u003eFunctions\u003c/a\u003e\n          \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#args_check\"\u003eargs_check()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#args_read\"\u003eargs_read()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#help\"\u003ehelp()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#help_synopsis\"\u003ehelp_synopsis()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#init_check_pre\"\u003einit_check_pre()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#init_check_post\"\u003einit_check_post()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#init_first\"\u003einit_first()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#init_lang\"\u003einit_lang()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#init_update\"\u003einit_update()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#main\"\u003emain()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#main_daemon\"\u003emain_daemon()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#main_interactive\"\u003emain_interactive()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#main_script\"\u003emain_script()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#menu_main\"\u003emenu_main()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#msg\"\u003emsg()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#run\"\u003erun()\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#trap_main\"\u003etrap_main()\u003c/a\u003e\u003c/li\u003e\n          \u003c/ul\u003e\n        \u003c/li\u003e\n        \u003cli\u003e\n          \u003ca href=\"#additional-sample-code\"\u003eAdditional Sample Code\u003c/a\u003e\n          \u003cul\u003e\n            \u003cli\u003e\u003ca href=\"#sample-parameters-and-constants\"\u003eSample Parameters and Constants\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#sample-actions\"\u003eSample Actions\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#sample-functions\"\u003eSample Functions\u003c/a\u003e\u003c/li\u003e\n            \u003cli\u003e\u003ca href=\"#daemon-mode-sample\"\u003eDaemon Mode Sample\u003c/a\u003e\u003c/li\u003e\n          \u003c/ul\u003e\n        \u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#adding-support-for-other-languages\"\u003eAdding support for other languages\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#further-code-samples\"\u003eFurther Code Samples\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#usage-srcrunsh-example\"\u003eUsage (/src/run.sh) (Example)\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#roadmap\"\u003eRoadmap\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#contributing\"\u003eContributing\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#license\"\u003eLicense\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#contact\"\u003eContact\u003c/a\u003e\u003c/li\u003e\n    \u003cli\u003e\u003ca href=\"#acknowledgments\"\u003eAcknowledgments\u003c/a\u003e\u003c/li\u003e\n  \u003c/ol\u003e\n\u003c/details\u003e\n\n\n\n\u003c!-- ABOUT THE PROJECT --\u003e\n## About The Project\n\nThis is a (mostly) **POSIX-/Bourne-Shell(sh)-compliant** repository template that provides boilerplates for\n\n* **checking requirements**, e.g. commands, (running) services, superuser rights, etc.  \n\n  ![Screenshot 11][screenshot11]\n\n* **checking and parsing arguments**  \n\n  ![Screenshot 21][screenshot21]\n\n* generating **well-formatted help (`-h|--help`) messages**  \n\n  ![Screenshot 31][screenshot31]\n\n* **interactive** (`dialog`-based) menus  \n\n  ![Screenshot 41][screenshot41]\n\n* **multi-language support** in terminal and/or `dialog` messages where the system's current language is automatically detected  \n\n  ![Screenshot 51][screenshot51]![Screenshot 52][screenshot52]\n\n* defining **trap handlers**, e.g. for cleanup operations on exit  \n\n  ![Screenshot 61][screenshot61]\n\n* **PID based locking** ensuring that only one instance runs at a time  \n\n  ![Screenshot 71][screenshot71]\n\n* **daemon mode (with sample code for parallel file processing)**  \n\n  ![Screenshot 81][screenshot81]\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n### Built With\n\n[![Shell Script][Shell Script-shield]][Shell Script-url]\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n### Testing Environment\n\nThe project has been developed and tested on the following system:\n\n| Info | Description\n---: | ---\nOS | Debian GNU/Linux 12 (bookworm)\nKernel | 5.15.133.1-microsoft-standard-WSL2\nPackages | [coreutils (9.1-1)](https://packages.debian.org/bookworm/coreutils)\n|| [dash (0.5.12-2)](https://packages.debian.org/bookworm/dash)\n|| [dialog (1.3-20230209-1)](https://packages.debian.org/bookworm/dialog)\n|| [libc-bin (2.36-9+deb12u3)](https://packages.debian.org/bookworm/libc-bin)\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- GETTING STARTED --\u003e\n## Getting Started\n### Prerequisites\nPlease make sure that the following dependencies are installed:\n\n* a POSIX-compatible shell, e.g. [Debian Almquist Shell (dash)](http://gondor.apana.org.au/~herbert/dash/), and\n* [Dialog](https://invisible-island.net/dialog/dialog.html), a tool to provide interactive dialog boxes within terminals.\n\nBelow you can find distribution-specific installation instructions.\n\n#### Alpine Linux\n```sh\nsudo apk add coreutils dialog\n```\n\n#### Debian\n```sh\nsudo apt install coreutils dash dialog libc-bin\n```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n### Installation\n1. Clone the repo\n\t```sh\n   git clone --recurse-submodules https://github.com/fkemser/SHtemplate.git\n   ```\n\n2. Open the repository with your favourite code editor. Search and replace the following placeholders (including `\u003c\u003e`) in **all** files:\n\n  \u003e :exclamation: The placeholders highlighted in **bold** are mandatory and must not be empty.\n\n  | \u003c...\u003e                   | Description                                                                  | Example                                                            |\n  |-------------------------|------------------------------------------------------------------------------|--------------------------------------------------------------------|\n  | **\u003cABOUT_AUTHORS\u003e**     | Author name and mail address (multiple authors separated by newline)         | John Doe (john.doe@example.com)\u003cbr\u003eJane Doe (jane.doe@example.com) |\n  | **\u003cABOUT_DESCRIPTION\u003e** | One-line description of what the project is about. Please start with a low letter and leave the terminating  '.' out. | a script based on `SHtemplate` used to ... |\n  | \u003cABOUT_INSTITUTION\u003e     | Institution (multiple lines allowed)                                         | Example Inc.\u003cbr\u003e123 Main Street\u003cbr\u003eAnytown, CA 12345\u003cbr\u003eUSA        |\n  | \u003cABOUT_LICENSE\u003e         | Project license (SPDX-License-Identifier) [^1]                               | GPL-3.0-or-later                                                   |\n  | \u003cABOUT_LOGO\u003e            | ASCII logo to display when running the script in interactive (`dialog`) mode | -                                                                  |\n  | **\u003cABOUT_PROJECT\u003e**     | Project/Repository title                                                     | My Project                                                         |\n  | \u003cABOUT_VERSION\u003e         | Release/Version number                                                       | 1.0.0                                                              |\n  | **\u003cABOUT_YEARS\u003e**       | Project year(s)                                                              | 2023-2024                                                          |\n\n  [^1]: For the full SPDX license list please have a look at 'https://spdx.org/licenses/'. However, only some licenses are supported so far, see `/lib/SHtemplateLIB/lib/licenses` folder. If you are not sure which license to choose just have a look at e.g. 'https://choosealicense.com'.\n\n3. The following folders and files are only used by this README and can be safely deleted:\n\n\t```sh\n   cd ./SHtemplate\n   rm -r res\n   rm README.md\n\t```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n### Customization\nBefore you continue to [customize the template](#template-structure) it is recommended to **ask yourself the following questions**:\n\n- What are the main goals of my script?\n- How shall this script be run? As a (normal) script, interactively, (infinitely) as a daemon, or mixedly?\n- Which parameters do I need, which arguments are allowed?\n- Which commands/packages have to be installed before?\n- Are there any other requirements?\n- Should there be any special handling on exit and/or interrupt, e.g. cleanup procedures?\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- TEMPLATE STRUCTURE --\u003e\n## Template Structure\n\n\u003c!-- Overview --\u003e\n### Overview\nThe template is separated into **multiple files** where each file does a different job.\n\n| /     | /                                             | / | Description                                                         |\n|-------|-----------------------------------------------|---|---------------------------------------------------------------------|\n| etc   |                                               | |                                                                       |\n|       | [`run.cfg.sh`](#etcruncfgsh)                  | | Configuration File (`/src/run.sh`)                                    |\n|       | [`\u003c...\u003e.cfg.sh`](#etcruncfgsh)                | | Further Configuration Files                                           |\n| lib   |                                               | |                                                                       |\n|       | [SHlib][SHlib-url]                            | | Shell Library (submodule)                                             |\n|       | [SHtemplateLIB][SHtemplateLIB-url]            | | SHtemplate Library (submodule)                                        |\n|       | [`...`](#lib)                                 | | Further libraries / library subdirectories                            |\n| src   |                                               | |                                                                       |\n|       | lang                                          | |                                                                       |\n|       |                                               | [`run.0.lang.sh`](#srclangrunlangsh-repository-string-constants-files)  | Language-Independent String Constants File (`/src/run.sh`)                                                                                                                              |\n|       |                                               | [`run.\u003cll\u003e.lang.sh`](#srclangrunlangsh-repository-string-constants-files)  | Language-Specific String Constants Files (`/src/run.sh`)                                                                                                                              |\n|       |                                               | [`\u003c...\u003e.lang.sh`](#further-string-constants-files-srclanglangsh) | Further String Constants Files                                                                                                                             |\n|       | [`init.sh`](#srcinitsh)                       | | Repository Initialization Script                                      |\n|       | **[`run.sh`](#srcrunsh-repository-run-file)** | | **Repository Run File**                                               |\n| test  | [`...`](#test)                                | | Test folder, only used for [Daemon Mode Sample](#daemon-mode-sample)  |\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\u003c!-- /etc/run.cfg.sh --\u003e\n### `/etc/run.cfg.sh`\nUse this file to introduce **constants and variables that the user can set before(!) running** `run.sh`. To better structure your code you can define multiple configuration files. To do so, please make sure that all files\n\n* have the file extension `.cfg.sh` and\n* are stored within `/etc/`.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#overview\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n\n\u003c!-- /lib/... --\u003e\n### `/lib/...`\nThis is the place to **add further shell libraries**. By default [SHlib (`/lib/SHlib`)][SHlib-url] and [SHtemplateLIB (`/lib/SHtemplateLIB`)][SHtemplateLIB-url] are already included.\n\n\u003e :exclamation: Please do not delete `/lib/SHlib` and `/lib/SHtemplateLIB` as the template relies on them.\n\n**To add your own library** files please make sure that they\n\n* have the file extension `.lib.sh` and\n* are stored within one of the following paths:\n\n  ```\n  /lib/\u003cfilename\u003e.lib.sh\n  /lib/\u003csubdir\u003e/\u003cfilename\u003e.lib.sh\n  /lib/\u003csubdir\u003e/lib/\u003cfilename\u003e.lib.sh\n  ```\n\n**In case you would like to add an existing repository** just change into the template's root directory and **add it as a submodule**, e.g.\n\n  ```sh\n  cd \u003crootdir\u003e\n  git submodule add https://github.com/fkemser/SHlib lib/SHlib\n  ```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#overview\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n\n\u003c!-- /src/init.sh --\u003e\n### `/src/init.sh`\nThis file is loaded by [`/src/run.sh`](#srcrunsh-repository-run-file) to initialize the repository, e.g. by setting file/folder structure, loading libraries, etc. Use this file to **publish additional file/folder paths (constants) within your repository.**\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#overview\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- /src/lang/run.\u003c...\u003e.lang.sh --\u003e\n## `/src/lang/run.\u003c...\u003e.lang.sh` (Repository String Constants Files)\nUse these files to store **string constants for help messages, command outputs, interactive menus, etc.** Afterwards you can reference them in [`/src/run.sh`](#srcrunsh-repository-run-file) by using their constant identifiers.\n  \nFor better code readability and maintenance the **constants are distributed over multiple files**: `run.0.lang.sh` for **language-independent** constants and\n `run.\u003cll\u003e.lang.sh` for **language-specific** constants where `\u003cll\u003e` in the filename is the language's [ISO 639-1][iso639-1-url] ID in lowercase letters, e.g. `run.en.lang.sh` contains all English strings, `run.de.lang.sh` all German strings, etc.\n\n\u003e :warning: Regarding the constant identifiers: Please follow the **naming convention below**, otherwise certain features, e.g. the semi-automatic creation of the script's help, will not work correctly.\n\n### Used in interactive (`dialog`) menus\nFor more information please run `dialog --help` or `man dialog`.\n\n| Constant                            | Example (identifier)                   | Description | Parameter (`dialog`) |\n|-------------------------------------|----------------------------------------|-------------|----------------------|\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_DLG\\_ITM\\_`\u003cREF\u003e` | L\\_RUN\\_EN\\_DLG\\_ITM\\_ARG\\_ITEM\\_ITEM1 | List item   | (item1)...           |\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_DLG\\_TTL\\_`\u003cREF\u003e` | L\\_RUN\\_EN\\_DLG\\_TTL\\_ARG\\_ITEM        | Title       | [--title (title)]    |\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_DLG\\_TXT\\_`\u003cREF\u003e` | L\\_RUN\\_EN\\_DLG\\_TXT\\_ARG\\_ITEM        | Text        | (text)               |\n\n### Used in `help()`, parameter section (`SYNOPSIS`)\n| Constant                            | Example (identifier)           | Example (value)                                       | Description           |\n|-------------------------------------|--------------------------------|-------------------------------------------------------|-----------------------|\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_HLP\\_DES\\_`\u003cREF\u003e` | L\\_RUN\\_EN\\_HLP\\_DES\\_ARG\\_INT | Help (arg_int)                                        | Parameter description |\n| L\\_`\u003cS\u003e`\\_HLP\\_PAR\\_`\u003cREF\u003e`         | L\\_RUN\\_HLP\\_PAR\\_ARG\\_INT     | -i\\|--int (int)                                       | Parameter cmd switch  |\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_HLP\\_REF\\_`\u003cREF\u003e` | L\\_RUN\\_EN\\_HLP\\_REF\\_ARG\\_INT | Use '-i\\|--int (int)' to specify \\\u003carg_int\\\u003e's value. | Reference description |\n\n### Used in `help()`, other sections\n| Constant                                        | Description           | Example (identifier)                  | Example (value)         |\n|-------------------------------------------------|-----------------------|---------------------------------------|-------------------------|\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_HLP\\_TTL\\_EXAMPLES\\_`\u003cI\u003e`     | Example (Title)       | L\\_RUN\\_EN\\_HLP\\_TTL\\_EXAMPLES\\_1     | Show Help               |\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_HLP\\_TXT\\_EXAMPLES\\_`\u003cI\u003e`     | Example (Text)        | L\\_RUN\\_EN\\_HLP\\_TXT\\_EXAMPLES\\_1     | ./run.sh --help         |\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_HLP\\_TXT\\_NOTES\\_`\u003cI\u003e`        | Note (Text)           | L\\_RUN\\_EN\\_HLP\\_TXT\\_NOTES\\_1        | This is the first note. |\n| L\\_`\u003cS\u003e`\\_HLP\\_TXT\\_REFERENCES\\_`\u003cI\u003e`           | Reference             | L\\_RUN\\_HLP\\_TXT\\_REFERENCES\\_1       | https://www.example.com |\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_HLP\\_TTL\\_REQUIREMENTS\\_`\u003cI\u003e` | Requirements (Title)  | L\\_RUN\\_EN\\_HLP\\_TTL\\_REQUIREMENTS\\_1 | General                 |\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_HLP\\_TXT\\_REQUIREMENTS\\_`\u003cI\u003e` | Requirements (Text)   | L\\_RUN\\_EN\\_HLP\\_TXT\\_REQUIREMENTS\\_1 | To run this ...         |\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_HLP\\_TTL\\_TLDR\\_`\u003cI\u003e`         | TL;DR (Title)         | L\\_RUN\\_EN\\_HLP\\_TTL\\_TLDR\\_1         | Requirements            |\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_HLP\\_TXT\\_TLDR\\_`\u003cI\u003e`         | TL;DR (Text)          | L\\_RUN\\_EN\\_HLP\\_TXT\\_TLDR\\_1         | Please install ...      |\n\n### Used in terminal output (`stdout`/`stderr`)\n| Constant                    | Description                             | Example (identifier)   | Example (value)  |\n|-----------------------------|-----------------------------------------|------------------------|------------------|\n| L\\_`\u003cS\u003e`\\_`\u003cLL\u003e`\\_TXT\\_`\u003cT\u003e` | Custom language-specific text constants | L\\_RUN\\_TXT\\_TEXT1\\_EN | Text 1 (English) |\n\n### Placeholders\n| \\\u003c...\\\u003e | Description                                                             | Example(s)                        |\n|---------|-------------------------------------------------------------------------|-----------------------------------|\n| `\u003cI\u003e`   | Index, starting from 1                                                  | 1                                 |\n| `\u003cLL\u003e`  | Language ID ([ISO 639-1][iso639-1-url])                                 | EN                                |\n| `\u003cREF\u003e` | Function, parameter, or parameter (list) value this constant refers to  | HELP, ARG_ACTION, ARG_ACTION_HELP |\n| `\u003cS\u003e`   | Reverse script (file) name without '.sh'                                | RUN                               |\n| `\u003cT\u003e`   | Identifier that describes what the string is about                      | ERR_NOT_FOUND                     |\n\n### Further String Constants Files (/src/lang/*.lang.sh)\nTo better structure your code you can define multiple string constant files. To do so, please make sure that all files\n\n* have the file extension `.lang.sh` and\n* are stored within `/src/lang/`.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#overview\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- /src/run.sh --\u003e\n## `/src/run.sh` (Repository Run File)\n\u003e :warning: The following sections only give a brief overview. Before running any of these functions **please have a look at the comments in the source files**.\n\nThis is the **repository's run file** so this is the **right place to add your code**. A good way to start is to **search for the `TODO:` sections within the source code**. They will guide you through the template and tell you where to add which part of your code.\n\nThe **template's design principle** is based on so called **modes** and **actions**.\n\n### Modes\nA **mode** defines **how the script is executed**. The template supports four different modes:\n\n| Mode        | Description                         |\n|-------------|-------------------------------------|\n| daemon      | Infinite (background/daemon) mode |\n| interactive | Interactive mode using `dialog`     |\n| script      | Classic script mode                 |\n| submenu     | Like `interactive` but with the intention to run one certain submenu and then exit. Usually used by other scripts to skip the welcome dialog and the main menu. |\n\n\u003e :information_source: Your script does not have to support all modes.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#overview\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n### Actions\nAn **action** consists of **one or multiple commands that the user can trigger** when calling the script. The template is shipped with three **essential** and six sample actions:\n\n| Action              | Description                                 |\n|---------------------|---------------------------------------------|\n| **about**           | Print dialog with information about your repository (authors, license, etc.). Only used in interactive mode. |\n| **help**            | Show the script's help.                     |\n| **exit**            | Exit script. Only used in interactive mode. |\n| custom1 ... custom6 | [Sample actions 1 - 6](#sample-actions)     |\n\n\u003e :warning: You can replace or delete the sample actions but **not** the essential ones.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#overview\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n### Constants\nTo provide certain features, e.g. the semi-automatic creation of `help()`, the script relies on certain constants, variables, and functions:\n\n| Constant                            | Description                                     |\n|-------------------------------------|-------------------------------------------------|\n| **`ARG_ACTION_LIST_INTERACTIVE`** / **`ARG_ACTION_LIST_SCRIPT`** | Lists of allowed actions `ARG_ACTION_...` in interactive, submenu, and script mode. Used for auto-generating help's `SYNOPSIS` section and the main menu in interactive/submenu mode. |\n| `ID_LANG`                           | Current language ID (ISO 639-1), see [`init_lang()`](#init_lang).\n| `INSTANCES`                         | Instance counter. Used to check if this script was called recursively.\n| **`LIST_ARG`**                      | Lists of compatible parameters (script mode only). Used for auto-generating help's `SYNOPSIS` section. |\n| **`LIST_ARG_CLEANUP_INTERACTIVE`**  | List of arguments that have to be cleared or reset to their default values after running [`run()`](#run) function (interactive mode only).              |\n| **`PIDLOCK_ENABLED`**               | Enable PID based locking? (`true\\|false`) :warning: If enabled (true) the script requires superuser privileges. :warning:                             |\n| **`T_DAEMON_SLEEP`**                | Daemon mode sleep interval (in s), see [Daemon Mode Sample](#daemon-mode-sample). |\n\n\u003e :warning: Please edit the constants highlighted in **bold** to adapt the script's behaviour and appearance to your code.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#overview\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n### Variables\n\n| Variable          | Description                                                   |\n|-------------------|---------------------------------------------------------------|\n| `arg_action`      | Current script action, see [Actions](#actions)                |\n| `arg_logdest`     | Log destination (terminal, `syslog`, both), see [msg()](#msg) |\n| `arg_mode`        | Current script operation mode, see [Modes](#modes)            |\n| `trap_blocked`    | Prevent trap execution? (`true\\|false`) Can be used to [temporarily disable trap handling](#temporarily-disable-trap-handling). |\n| `trap_triggered`  | `trap_...()` function was called? (`true\\|false`) Used to decide if trap handling has to be (manually) launched after [temporarily disabling it](#temporarily-disable-trap-handling). |\n\n\u003e :exclamation: Please **do not delete or change** any of the variables as the template heavily relies on them.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#overview\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n### Functions\n\n| Function                                | Description / Task                                              |\n|-----------------------------------------|-----------------------------------------------------------------|\n| [`args_check()`](#args_check)           | Check if passed arguments are valid                             |\n| [`args_read()`](#args_read)             | Read/Parse arguments                                            |\n| `error()`                               | See [`msg()`](#msg)                                             |\n| [`help()`](#help)                       | Print help message using `less` utility                         |\n| [`help_synopsis()`](#help_synopsis)     | Create help's `SYNOPSIS` section                                |\n| `info()`                                | See [`msg()`](#msg)                                             |\n| [`init_check_pre()`](#init_check_pre)   | Check script requirements **before** argument parsing           |\n| [`init_check_post()`](#init_check_post) | Check script requirements **after** argument parsing            |\n| [`init_first()`](#init_first)           | Set default log destination, (optionally) lock the script (PID file), install trap handler and run other commands that need to be executed right at the beginning.                                                   |\n| [`init_lang()`](#init_lang)             | Set language-specific text constants                            |\n| [`init_update()`](#init_update)         | Update global variables/constants and perform initialization commands that should be executed **after** argument parsing                                                                                            |\n| [`main()`](#main)                       | Main function                                                   |\n| [`main_daemon()`](#main_daemon)         | Main subfunction (daemon mode)                                  |\n| [`main_interactive()`](#main_interactive) | Main subfunction (interactive / submenu mode)                 |\n| [`main_script()`](#main_script)         | Main subfunction (script mode)                                  |\n| [`menu_main()`](#menu_main)             | Main menu (interactive mode)                                    |\n| [`msg()`](#msg)                         | Log/Print error/info/warning message and optionally exit        |\n| [`run()`](#run)                         | Perform one certain action (cycle)                              |\n| [`trap_main()`](#trap_main)             | Trap (cleanup and exit) function for this script                |\n| `warning()`                             | See [`msg()`](#msg)                                             |\n\n\u003e :exclamation: All functions are essential and **must not be deleted**. However, you should edit them within the `TODO:` sections to adapt the script to your needs.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#overview\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `args_check()`\nUse this function to **check if passed arguments are valid**. You will already find some sample checks, e.g.\n\n* file/folder checks,\n* data type checks,\n* regex checks,\n* value range checks.\n\n\u003e :information_source: For more checks please have a look at the functions `lib_core_is()` and `lib_core_regex()` in [`lib/SHlib/lib/core.lib.sh`](https://github.com/fkemser/SHlib/blob/432d56b38dc795aa98d59fe185921d38cc21637c/lib/core.lib.sh)\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `args_read()`\nEdit this function to **add your individual command line parameters (switches)**. Please do also not forget to\n\n* also add them to [`/src/lang/run.0.lang.sh`](#srclangrunlangsh-repository-string-constants-files),\n* write your help (`SYNOPSIS`) texts in [`/src/lang/run.\u003cll\u003e.lang.sh`](#srclangrunlangsh-repository-string-constants-files),\n* add them to [`help_synopsis()`](#help_synopsis), and\n* add the parameters' identifiers (names) to the template's [constants](#constants) (`ARG_ACTION_LIST_INTERACTIVE`, `ARG_ACTION_LIST_SCRIPT`, `LIST_ARG`, `LIST_ARG_CLEANUP_INTERACTIVE`), if relevant.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `help()`\nThis function prints the **help message** by using the `less` utility. By default the help consists of the following **sections**:\n\n| Section     | Description                                                             |\n|-------------|-------------------------------------------------------------------------|\n| TL;DR       | Quick start section                                                     |\n| REQUIREMENT | Software and/or hardware requirements                                   |\n| SYNOPSIS    | Usage instructions (command line switches, additional arguments, etc.)  |\n| EXAMPLES    | Command examples                                                        |\n| NOTES       | Notes that are referenced within other help sections                    |\n| REFERENCES  | References, e.g. URLs                                                   |\n| ABOUT       | Repository-related information (author, institution, license, etc.)     |\n\n\u003e :warning: Please **do not hardcode any help texts within this function**. Instead, edit [`/src/lang/run.\u003c...\u003e.lang.sh`](#srclangrunlangsh-repository-string-constants-files) to define (write) your help texts and edit [`help_synopsis()`](#help_synopsis) to modify the `SYNOPSIS` section of your help.\n\n\u003e :information_source: For a full example just have a look at the [Usage](#usage-srcrunsh-example) section below.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `help_synopsis()`\nThis is the function that generates the `SYNOPSIS` (usage) section of the script's help (`-h|--help`).\nEdit this function to **\"publish\" your help texts that you have previously created in [`/src/lang/run.\u003c...\u003e.lang.sh`](#srclangrunlangsh-repository-string-constants-files)**.\n\n\u003e :information_source: The introduction containing the available actions `ACTION := { ... }` and options `OPTION := { ... }` is automatically created. This can be controlled via the constants `ARG_ACTION_LIST_SCRIPT` and `LIST_ARG`, see [Constants](#constants) section above.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `init_check_pre()`\nEdit this function to **perform mandatory and/or optional requirement checks before(!) argument parsing**, e.g.\n\n* available commands,\n* running services,\n* superuser rights.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `init_check_post()`\nEdit this function to **perform mandatory and/or optional requirement checks after(!) argument parsing**.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `init_first()`\nAs the name already states this is the first function (within [`main()`](#main)) that is executed directly after loading the initialization script [`/src/init.sh`](#srcinitsh) and running [`init_lang()`](#init_lang). It is responsible for **setting the right log destination**: In case the script is running within a terminal window, the script outputs all messages to `stdout/stderr` by default. Otherwise the script uses `syslog (logger)` for logging.\n\nFurthermore this function installs a **trap handler** that calls [`trap_main()`](#trap_main) allowing the script to safely exit, even on interrupts.\n\nEdit this function in case you would like to\n* **modify the trap handler (signals, arguments) for [`trap_main()`](#trap_main)**,\n* **add further initialization commands**\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `init_lang()`\nThis function detects your system's default language and stores its [ISO 639-1][iso639-1-url] ID in `ID_LANG`. This constant is used to generate language-dependent terminal, log, and `dialog` messages.\n\nEdit this function in case you\n * would like **to add support for other languages**, or\n * have **text strings for custom terminal/log messages**.\n\n\u003e :warning: Before editing this function please make sure that this [template already supports your language](#adding-support-for-other-languages) and that all language-specific texts (constants) have been defined in [`/src/lang/run.\u003cll\u003e.lang.sh`](#srclangrunlangsh-repository-string-constants-files).\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `init_update()`\nEdit this function to **set constants/variables and run commands after(!) all arguments have been parsed and checked**.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `main()`\nThis is the script's entry point so it is the **first function to be called**. In most cases there is no need to edit this function. Instead, **edit the mode-specific main functions `main_...()` right below**.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `main_daemon()`\nThis the script's **entry point** for running in **daemon** mode.\n\n\u003e :information_source: This function is shipped with some sample code to demonstrate the daemon mode. See also [`here`](#daemon-mode-sample).\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `main_interactive()`\nThis the script's **entry point** for running in **interactive or submenu** mode.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `main_script()`\nThis the script's **entry point** for running in **(classic) script** mode.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `menu_main()`\nThis function controls the **program flow for interactive and submenu** mode. Edit this function, e.g. to **define which `dialog` menus appear for which actions**.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `msg()`\nThis function is responsible for **generating terminal and `syslog` messages**. It automatically detects the log destination depending on the user's manual setting (`--log \u003cdest\u003e`) and the current environment (interactive terminal, cron, etc.). The functions `error()`, `info()`, and `warning()` are wrapper functions to generate error/info/warning messages. In most cases there is no need to edit this function but you can **call it (or its wrappers) from your own functions to generate terminal/syslog messages**.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `run()`\nThis is the central function for **all modes but daemon mode**:\nHere you define **all commands that should be executed depending on the action and other parameters that the user has previously set**, no matter if via command line arguments or interactively.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n#### `trap_main()`\nThis is the script's main trap function and is (by default) executed on exit or when the script is interrupted.\nEdit this function to **define your individual trap handling routine**.\n\n\u003e :information_source: To define the signals on which `trap_main()` should be triggered please have a look at [`init_first()`](#init_first).\n\n\u003e :information_source: You can also disable trap handling temporarily, e.g. when running some code that should not be interrupted. See section [Further Code Samples](#further-code-samples).\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#functions\"\u003eback to overview\u003c/a\u003e)\u003c/p\u003e\n\n\n### Additional Sample Code\nBesides the basic template, [`/src/run.sh`](#srcrunsh-repository-run-file) is also shipped with some sample actions, parameters, and functions. They **do not serve any specific purpose but are just for showing you the possibilities of the script**. In contrast to the [basic template](#srcrunsh-repository-run-file) you can safely delete or replace the parts described below.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n#### Sample Parameters and Constants\n\n| Parameter / Constant  | Description                                                                               |\n|-----------------------|-------------------------------------------------------------------------------------------|\n| `arg_arg_or_stdin`    | Sample parameter that either takes an argument or, if not set, `stdin`'s content          |\n| `arg_bool`            | Sample boolean parameter                                                                  |\n| `arg_dir`             | Sample directory parameter                                                                |\n| `arg_file`            | Sample file parameter                                                                     |\n| `arg_int`             | Sample integer parameter with a range of allowed values                                   |\n| `arg_item`            | Sample list item parameter                                                                |\n| `arg_password`        | Sample password parameter                                                                 |\n| `arg_str`             | Sample string parameter                                                                   |\n| `EXT_TEST`            | Test file extension for sample daemon, see also [Daemon Mode Sample](#daemon-mode-sample) |\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n#### Sample Actions\nThere are six sample actions (`custom1`...`custom6`). Each action behaves differently in the sense of how (in which [mode](#srcrunsh-repository-run-file)) it can be run and which parameters it requires or accepts.\n\nThe matrix below shows **which action can be run in which mode** ...\n\n| arg_action  | interactive | script  | submenu |\n|-------------|-------------|---------|---------|\n| custom1     | -           | x       | -       |\n| custom2     | x           | x       | x       |\n| custom3     | x           | x       | x       |\n| custom4     | x           | x       | x       |\n| custom5     | x           | x       | x       |\n| custom6     | -           | -       | x       |\n\n\u003e :information_source: The `daemon` mode is not listed here as it has its own function [`func1()`](#func1), see also [Daemon Mode Sample](#daemon-mode-sample).\n\n... where the second matrix shows **which of the actions require which parameter(s)**:\n\n| arg_action  | arg_arg_or_stdin  | arg_bool  | arg_dir | arg_file  | arg_int | arg_item  | arg_password  | arg_str |\n|-------------|-------------------|-----------|---------|-----------|---------|-----------|---------------|---------|\n| custom1     | -                 | -         | -       | -         | -       | -         | -             | -       |\n| custom2     | -                 | o         | -       | -         | -       | o         | -             | -       |\n| custom3     | -                 | -         | x       | -         | -       | -         | -             | -       |\n| custom4     | -                 | -         | -       | -         | x       | -         | -             | x       |\n| custom5     | (x)               | -         | -       | (x)       | -       | -         | -             | -       |\n| custom6     | -                 | -         | -       | -         | -       | -         | -             | -       |\n\n| ... | Meaning                         |\n|-----|---------------------------------|\n|  -  | not relevant                    |\n|  o  | optional (in script mode they can be passed via their command line switches, in interactive (and submenu) mode there is a dialog that can be skipped) |\n|  x  | mandatory                       |\n| (x) | mandatory but either ... or ... |\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n#### Sample Functions\n\n| Function                        | Description                                                                   |\n|---------------------------------|-------------------------------------------------------------------------------|\n| [`func1()`](#func1)             | Sample function that can be run either in script mode or daemon mode          |\n| [`menu_arg_...()`](#menu_arg_)  | `dialog` menus for setting sample parameters in interactive and submenu mode  |\n| [`trap_func1()`](#trap_func1)   | Trap (cleanup and exit) function for `func1()` (daemon mode only)             |\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n##### `func1()`\nThis is **an example on how to write functions that can run in both, script mode and daemon mode**. As a sample function it does not fulfill a certain purpose. It simply processes a given file by printing its name and a message, either to the terminal (script mode) or to `syslog` (daemon mode).\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n##### `menu_arg_...()`\nThese functions provide the interactive `dialog`-based menus for setting the sample parameters listed above, e.g. `menu_arg_bool()` is the menu for setting `arg_bool`.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n##### `trap_func1()`\nThis is `func1()` 's special trap function and is only used if the script is running in daemon mode. Edit this function to **define your individual trap handling routine for `func1()` when running the script in daemon mode**.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n#### Daemon Mode Sample\nIn daemon mode [`main_daemon()`](#main_daemon) runs [`func1()`](#func1) not only for a single file but over all files with a pre-defined extension (`EXT_TEST`) within a pre-defined folder (`arg_dir`). This is done parallelly, meaning that there are running **multiple instances** of [`func1()`](#func1), one per file, running in a **subshell**.\n\nTo allow the subshells to terminate safely on signals, e.g. `SIGTERM`, [`func1()`](#func1) installs [`trap_func1()`](#trap_func1) as a trap handler within the subshell.\n\nTo let the daemon mode run infinitely there are two loops: One within [`func1()`](#func1) (within each subshell) and a second one in [`main_daemon()`](#main_daemon) (within the calling script). The latter is just a backup: In case a subshell crashes, it gets \"respawned\" within a maximum period of time that can be defined via the constant `T_DAEMON_SLEEP`.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- MULTI-LANGUAGE SUPPORT --\u003e\n## Adding support for other languages\nTo add support for other languages please follow these steps:\n\n1. First check whether [SHtemplateLIB](https://github.com/fkemser/SHtemplateLIB#adding-support-for-other-languages), the template's own library, supports your language. If not, please follow the translation instructions there before continuing.\n\n2. Create your project/repository-specific translation file [`/src/lang/run.\u003cll\u003e.lang.sh`](#srclangrunlangsh-repository-string-constants-files) where `\u003cll\u003e` in the filename is the language's [ISO 639-1][iso639-1-url] ID in lowercase letters, e.g. create `run.`**`es`**`.lang.sh` to store **`Spanish`** strings.\n\n3. To finally enable support for the new language: Open [`/src/run.sh`](#srcrunsh-repository-run-file) and look for the `init_lang()` function. Add your language's [ISO 639-1][iso639-1-url] ID within the `TODO:` section, e.g. to support Spanish (`ES`), simply add:\n\n```sh\ncase \"${ID_LANG}\" in\n  ...\n  ${LIB_C_ID_LANG_ES}) readonly ID_LANG=\"${LIB_C_ID_L_ES}\";;\n  ...\nesac\n```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- FURTHER CODE SAMPLES --\u003e\n## Further Code Samples\nThere are some code snippets that did not fit into the template but yet they are worth to be mentioned.\n\n### Run a certain command (`\u003ccmd\u003e`) and in case of any error do not only log a pre-defined error message (`\u003cmsg\u003e`) but also the command's previous output (`\u003cresult\u003e`)\n```sh\nexec 3\u003e\u00261\n  result=\"$(\u003ccmd\u003e 2\u003e\u00261 1\u003e\u00263; exit $?)\" # TODO: Replace \u003ccmd\u003e by your own value.\n  exitcode=\"$?\"\nexec 3\u003e\u0026-\nif [ ${exitcode} -ne 0 ]; then\n  # ...                             # TODO: Put your error handling here.\n  msg=\"\u003cmsg\u003e\"                       # TODO: Replace \u003cmsg\u003e by your own value.\n  error \"${msg}\" \"${result}\"\nfi\n```\n\n### Temporarily disable trap handling\n```sh\ntrap_blocked=\"true\"   # Disable trap handling\n# ...\n# TODO: Put commands here that should not(!) be interrupted\n# ...\ntrap_blocked=\"false\"  # Re-enable trap handling\n\n# Run trap handling (manually) if trap was previously triggered\nif ${trap_triggered}; then\n  if ${is_subshell}; then trap_func1; else trap_main; fi\nfi\n```\n\n### Check whether the script was called recursively\n```sh\nif eval [ \\${${INSTANCES}} -gt 1 ]; then echo \"Script recursively called\"; fi\n```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- USAGE (HELP) --\u003e\n## Usage (/src/run.sh) (Example)\n\n```sh\n================================================================================\n==============================     SHtemplate     ==============================\n=======================     (Press 'q' to quit ...)     ========================\n================================================================================\n\nA template repository for Bourne-Shell (sh) projects.\n\n================================================================================\n================================     TL;DR     =================================\n================================================================================\n\n_________________________________ Requirements _________________________________\n\nTo install the necessary packages on your system, simply run:\n\nDebian\n\u003e sudo apt install dialog (...)\n\n(...further requirements...)\n\nThe script has been developed and tested on the following system:\n\nOS:         ... (Run 'cat /etc/*release')\nKernel:     ... (Run 'uname -r')\nPackages:   Dialog (...), (...)\n\n___________________________________ Synopsis ___________________________________\n\nThere are multiple ways to run this script. For more information please have a look at \u003cSYNOPSIS\u003e section below.\n\nInteractive mode (without any args):\n\u003e ./run.sh\n\nClassic (script) mode:\n\u003e ./run.sh [ OPTION ]... ACTION [\u003cfile\u003e]\n\n================================================================================\n=============================     REQUIREMENTS     =============================\n================================================================================\n\n___________________________________ General ____________________________________\n\nRequired Packages:\n  General: (...)\n  Debian:  \u003e sudo apt install (...)\n\nOptional Packages:\n  General: (...)\n  Debian:  \u003e sudo apt install (...)\n\n(...)\n\n_________________________ Interactive Mode (optional) __________________________\n\nIn case you run this script interactively (see \u003cSYNOPSIS\u003e below)\nyour terminal window must have a size of \u003c100x30\u003e or bigger.\n\nRequired Packages:\n  General: Dialog\n   Debian: \u003e sudo apt install dialog\n\n================================================================================\n===============================     SYNOPSIS     ===============================\n================================================================================\n\nThere are multiple ways to run this script:\n\nInteractive mode (without any args):\n\u003e ./run.sh\n\nClassic (script) mode:\n\u003e ./run.sh [ OPTION ]... ACTION [\u003cfile\u003e]\n\nACTION := { -h|--help | --custom1 | --custom2 | --custom3 \u003cdir\u003e | --custom4 \u003cint\u003e \u003cstr\u003e | --custom5 [\u003cfile\u003e] }\n\nOPTION := { [-b|--bool] | [-f|--file \u003cfile\u003e] | [-i|--int \u003cint\u003e] | [-j|--item \u003citem\u003e] | [--log \u003cdest\u003e] | [-p|--password \u003cpwd\u003e] | [-s|--str \u003cstring\u003e] }\n\n[\u003cfile\u003e] : File to use\n\n--------------------------------------------------------------------------------\n--------------------------------     ACTION     --------------------------------\n--------------------------------------------------------------------------------\n\n-h|--help                 Show this help message                                \n\n-D|--daemon               Run this script in daemon (background) mode           \n\n--submenu \u003cmenu\u003e          Run a certain submenu interactively and exit          \n                                                                                \n                          \u003cmenu\u003e = { custom2 | custom3 | custom4 | custom5 |    \n                          custom6 }                                             \n\n--custom1                 Help \u003cARG_ACTION_CUSTOM1\u003e                             \n\n--custom2                 Help \u003cARG_ACTION_CUSTOM2\u003e Use '-b|--bool' to enable   \n                          \u003carg_bool\u003e. Use '-j|--item \u003citem\u003e' to specify         \n                          \u003carg_item\u003e's value.                                   \n\n--custom3 \u003cdir\u003e           Help \u003cARG_ACTION_CUSTOM3\u003e. Regarding \u003cdir\u003e please     \n                          have a look at '-d|--dir \u003cdir\u003e'.                      \n\n--custom4 \u003cint\u003e \u003cstr\u003e     Help \u003cARG_ACTION_CUSTOM4\u003e. Regarding \u003cint\u003e and \u003cstr\u003e  \n                          please have a look at '-i|--int \u003cint\u003e' and '-s|--str  \n                          \u003cstring\u003e'.                                            \n\n--custom5 [\u003cfile\u003e]        Help \u003cARG_ACTION_CUSTOM5\u003e. Either use a given \u003cfile\u003e  \n                          or \u003cstdin\u003e's (pipe) content ('echo \"string\" |         \n                          ./run.sh --custom5').                                 \n\n--custom6                 Help \u003cARG_ACTION_CUSTOM6\u003e                             \n\n--------------------------------------------------------------------------------\n--------------------------------     OPTION     --------------------------------\n--------------------------------------------------------------------------------\n\n--log \u003cdest\u003e            Specify where to write log message to                                   \n                                                                                \n                            both  :  Terminal + System log                      \n                          syslog  :  System log only                            \n                        terminal  :  Terminal only                              \n                                                                                \n                        (default: 'terminal')                                   \n\n-b|--bool               Help \u003carg_bool\u003e                                         \n\n-d|--dir \u003cdir\u003e          Help \u003carg_dir\u003e                                          \n\n-f|--file \u003cfile\u003e        Help \u003carg_file\u003e                                         \n\n-i|--int \u003cint\u003e          Help \u003carg_int\u003e                                          \n                                                                                \n                        \u003cint\u003e = [0, 10] (default: '1')                          \n\n-j|--item \u003citem\u003e        Help \u003carg_item\u003e                                         \n                                                                                \n                        item1  :  Help \u003cARG_ITEM_ITEM1\u003e                         \n                        item2  :  Help \u003cARG_ITEM_ITEM2\u003e                         \n                                                                                \n                        \u003citem\u003e = { item1 | item2 }                              \n                                                                                \n                        (default: 'item1')                                      \n\n-p|--password \u003cpwd\u003e     Help \u003carg_password\u003e. See also (1).                      \n                                                                                \n                        (default: '')                                           \n\n-s|--str \u003cstring\u003e       Help \u003carg_str\u003e                                          \n                                                                                \n                        (default: 'abc123')                                     \n\n================================================================================\n===============================     EXAMPLES     ===============================\n================================================================================\n\n__________________________________ Example 1 ___________________________________\n\n\u003e ./run.sh --custom1\n\n__________________________________ Example 2 ___________________________________\n\n\u003e ./run.sh --custom2 --item item2\n\n================================================================================\n================================     NOTES     =================================\n================================================================================\n\n_____________________________________ (1) ______________________________________\n\nIt is highly recommended to pass credentials only via environmental variables. To do so, just set this value to 'env:\u003cVAR\u003e' (without '' \u003c\u003e) where \u003cVAR\u003e is your environmental variable's name.\n\nPlease note that passing credentials in clear-text form can be highly insecure as any other user/process could display the command line of this application by using system utilities like 'ps'.\n\nExample: You would like to pass the password '123456'.\n\n  Via an environmental variable (preferred)\n    \u003e export mypwd=\"123456\"\n    \u003e ... \"env:mypwd\"\n\n  Directly, in clear-text form (NOT recommended)\n    \u003e ... \"123456\"\n\n_____________________________________ (2) ______________________________________\n\nThis is the text of note 2.\n\n================================================================================\n==============================     REFERENCES     ==============================\n================================================================================\n\n[1]     https://www.example.com                                                 \n\n[2]     https://www.example.org                                                 \n\n================================================================================\n================================     ABOUT     =================================\n================================================================================\n\n  AUTHORS\n    Florian Kemser and the SHtemplate contributors\n\n  COPYRIGHT\n    This file is part of SHtemplate, a template repository for \n    POSIX-/Bourne-Shell(sh) projects.\n    \n    Copyright (c) 2023-2024 Florian Kemser and the SHtemplate contributors\n    \n    Permission is hereby granted, free of charge, to any person obtaining a \n    copy of this software and associated documentation files (the \"Software\"), \n    to deal in the Software without restriction, including without limitation \n    the rights to use, copy, modify, merge, publish, distribute, sublicense, \n    and/or sell copies of the Software, and to permit persons to whom the \n    Software is furnished to do so, subject to the following conditions:\n    \n    The above copyright notice and this permission notice (including the next \n    paragraph) shall be included in all copies or substantial portions of the \n    Software.\n    \n    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \n    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \n    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE \n    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \n    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \n    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \n    DEALINGS IN THE SOFTWARE.\n```\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- ROADMAP --\u003e\n## Roadmap\n\nSee the [open issues](https://github.com/fkemser/SHtemplate/issues) for a full list of proposed features (and known issues).\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- CONTRIBUTING --\u003e\n## Contributing\n\nContributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.\n\nIf you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag \"enhancement\".\nDon't forget to give the project a star! Thanks again!\n\n1. Fork the Project\n2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)\n3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)\n4. Push to the Branch (`git push origin feature/AmazingFeature`)\n5. Open a Pull Request\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- LICENSE --\u003e\n## License\n\nDistributed under the **MIT License**. See [`LICENSE`][license-url] for more information.  \n\n\u003e :warning: The license above does not apply to the files and folders within the library directory `/lib`. Please have a look at the `LICENSE` file located in the root directory of each library to get more information.\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- CONTACT --\u003e\n## Contact\n\nProject Link: [https://github.com/fkemser/SHtemplate](https://github.com/fkemser/SHtemplate)\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- ACKNOWLEDGMENTS --\u003e\n## Acknowledgments\n###\n* [othneildrew/Best-README-Template](https://github.com/othneildrew/Best-README-Template)\n* [Ileriayo/markdown-badges](https://github.com/Ileriayo/markdown-badges)\n\n\u003cp align=\"right\"\u003e(\u003ca href=\"#readme-top\"\u003eback to top\u003c/a\u003e)\u003c/p\u003e\n\n\n\n\u003c!-- MARKDOWN LINKS \u0026 IMAGES --\u003e\n\u003c!-- https://www.markdownguide.org/basic-syntax/#reference-style-links --\u003e\n[contributors-shield]: https://img.shields.io/github/contributors/fkemser/SHtemplate.svg?style=for-the-badge\n[contributors-url]: https://github.com/fkemser/SHtemplate/graphs/contributors\n[forks-shield]: https://img.shields.io/github/forks/fkemser/SHtemplate.svg?style=for-the-badge\n[forks-url]: https://github.com/fkemser/SHtemplate/network/members\n[stars-shield]: https://img.shields.io/github/stars/fkemser/SHtemplate.svg?style=for-the-badge\n[stars-url]: https://github.com/fkemser/SHtemplate/stargazers\n[issues-shield]: https://img.shields.io/github/issues/fkemser/SHtemplate.svg?style=for-the-badge\n[issues-url]: https://github.com/fkemser/SHtemplate/issues\n[license-shield]: https://img.shields.io/github/license/fkemser/SHtemplate.svg?style=for-the-badge\n[license-url]: https://github.com/fkemser/SHtemplate/blob/main/LICENSE\n[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge\u0026logo=linkedin\u0026colorB=555\n[linkedin-url]: https://linkedin.com/in/linkedin_username\n\n[screenshot11]: res/screenshot11.png\n[screenshot21]: res/screenshot21.png\n[screenshot31]: res/screenshot31.gif\n[screenshot41]: res/screenshot41.gif\n[screenshot51]: res/screenshot51.png\n[screenshot52]: res/screenshot52.png\n[screenshot61]: res/screenshot61.png\n[screenshot71]: res/screenshot71.png\n[screenshot81]: res/screenshot81.png\n\n[SHlib-url]: https://github.com/fkemser/SHlib\n[SHtemplateLIB-url]: https://github.com/fkemser/SHtemplateLIB\n\n[iso639-1-url]: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes\n\n[LaTeX-shield]: https://img.shields.io/badge/latex-%23008080.svg?style=for-the-badge\u0026logo=latex\u0026logoColor=white\n[LaTeX-url]: https://www.latex-project.org/\n[Shell Script-shield]: https://img.shields.io/badge/shell_script-%23121011.svg?style=for-the-badge\u0026logo=gnu-bash\u0026logoColor=white\n[Shell Script-url]: https://pubs.opengroup.org/onlinepubs/9699919799/","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffkemser%2Fshtemplate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffkemser%2Fshtemplate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffkemser%2Fshtemplate/lists"}