├── .circleci └── config.yml ├── .config └── rubocop │ └── config.yml ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .ruby-version ├── CITATION.cff ├── Gemfile ├── LICENSE.adoc ├── README.adoc ├── Rakefile ├── bin ├── rake └── run ├── lib └── cli.sh └── settings └── main.sh /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | jobs: 3 | build: 4 | working_directory: ~/project 5 | docker: 6 | - image: bkuhlmann/alpine-ruby:latest 7 | steps: 8 | - checkout 9 | 10 | - restore_cache: 11 | name: Gems Restore 12 | keys: 13 | - gem-cache-{{.Branch}}-{{checksum "Gemfile"}} 14 | - gem-cache- 15 | 16 | - run: 17 | name: Gems Install 18 | command: | 19 | gem update --system 20 | bundle config set path "vendor/bundle" 21 | bundle install 22 | 23 | - save_cache: 24 | name: Gems Store 25 | key: gem-cache-{{.Branch}}-{{checksum "Gemfile"}} 26 | paths: 27 | - vendor/bundle 28 | 29 | - run: 30 | name: Rake 31 | command: bundle exec rake 32 | -------------------------------------------------------------------------------- /.config/rubocop/config.yml: -------------------------------------------------------------------------------- 1 | inherit_gem: 2 | caliber: config/all.yml 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [bkuhlmann] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Why 2 | 3 | 4 | ## How 5 | 6 | 7 | ## Notes 8 | 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | 4 | ## Screenshots/Screencasts 5 | 6 | 7 | ## Details 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.4.4 2 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: Please use the following metadata when citing this project in your work. 3 | title: Bashsmith 4 | abstract: A template for smithing Bash scripts. 5 | version: 6.6.0 6 | license: Hippocratic-2.1 7 | date-released: 2025-02-22 8 | authors: 9 | - family-names: Kuhlmann 10 | given-names: Brooke 11 | affiliation: Alchemists 12 | orcid: https://orcid.org/0000-0002-5810-6268 13 | keywords: 14 | - bash 15 | - shell 16 | - scripts 17 | - generator 18 | - templates 19 | - best practices 20 | repository-code: https://github.com/bkuhlmann/bashsmith 21 | repository-artifact: https://alchemists.io/projects/bashsmith 22 | url: https://alchemists.io/projects/bashsmith 23 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ruby file: ".ruby-version" 4 | 5 | source "https://rubygems.org" 6 | 7 | gem "caliber", "~> 0.79" 8 | gem "debug", "~> 1.10" 9 | gem "git-lint", "~> 9.0" 10 | gem "rake", "~> 13.2" 11 | -------------------------------------------------------------------------------- /LICENSE.adoc: -------------------------------------------------------------------------------- 1 | = Hippocratic License 2 | 3 | Version: 2.1.0. 4 | 5 | Purpose. The purpose of this License is for the Licensor named above to 6 | permit the Licensee (as defined below) broad permission, if consistent 7 | with Human Rights Laws and Human Rights Principles (as each is defined 8 | below), to use and work with the Software (as defined below) within the 9 | full scope of Licensor’s copyright and patent rights, if any, in the 10 | Software, while ensuring attribution and protecting the Licensor from 11 | liability. 12 | 13 | Permission and Conditions. The Licensor grants permission by this 14 | license ("License"), free of charge, to the extent of Licensor’s 15 | rights under applicable copyright and patent law, to any person or 16 | entity (the "Licensee") obtaining a copy of this software and 17 | associated documentation files (the "Software"), to do everything with 18 | the Software that would otherwise infringe (i) the Licensor’s copyright 19 | in the Software or (ii) any patent claims to the Software that the 20 | Licensor can license or becomes able to license, subject to all of the 21 | following terms and conditions: 22 | 23 | * Acceptance. This License is automatically offered to every person and 24 | entity subject to its terms and conditions. Licensee accepts this 25 | License and agrees to its terms and conditions by taking any action with 26 | the Software that, absent this License, would infringe any intellectual 27 | property right held by Licensor. 28 | * Notice. Licensee must ensure that everyone who gets a copy of any part 29 | of this Software from Licensee, with or without changes, also receives 30 | the License and the above copyright notice (and if included by the 31 | Licensor, patent, trademark and attribution notice). Licensee must cause 32 | any modified versions of the Software to carry prominent notices stating 33 | that Licensee changed the Software. For clarity, although Licensee is 34 | free to create modifications of the Software and distribute only the 35 | modified portion created by Licensee with additional or different terms, 36 | the portion of the Software not modified must be distributed pursuant to 37 | this License. If anyone notifies Licensee in writing that Licensee has 38 | not complied with this Notice section, Licensee can keep this License by 39 | taking all practical steps to comply within 30 days after the notice. If 40 | Licensee does not do so, Licensee’s License (and all rights licensed 41 | hereunder) shall end immediately. 42 | * Compliance with Human Rights Principles and Human Rights Laws. 43 | [arabic] 44 | . Human Rights Principles. 45 | [loweralpha] 46 | .. Licensee is advised to consult the articles of the United Nations 47 | Universal Declaration of Human Rights and the United Nations Global 48 | Compact that define recognized principles of international human rights 49 | (the "Human Rights Principles"). Licensee shall use the Software in a 50 | manner consistent with Human Rights Principles. 51 | .. Unless the Licensor and Licensee agree otherwise, any dispute, 52 | controversy, or claim arising out of or relating to (i) Section 1(a) 53 | regarding Human Rights Principles, including the breach of Section 1(a), 54 | termination of this License for breach of the Human Rights Principles, 55 | or invalidity of Section 1(a) or (ii) a determination of whether any Law 56 | is consistent or in conflict with Human Rights Principles pursuant to 57 | Section 2, below, shall be settled by arbitration in accordance with the 58 | Hague Rules on Business and Human Rights Arbitration (the "Rules"); 59 | provided, however, that Licensee may elect not to participate in such 60 | arbitration, in which event this License (and all rights licensed 61 | hereunder) shall end immediately. The number of arbitrators shall be one 62 | unless the Rules require otherwise. 63 | + 64 | Unless both the Licensor and Licensee agree to the contrary: (1) All 65 | documents and information concerning the arbitration shall be public and 66 | may be disclosed by any party; (2) The repository referred to under 67 | Article 43 of the Rules shall make available to the public in a timely 68 | manner all documents concerning the arbitration which are communicated 69 | to it, including all submissions of the parties, all evidence admitted 70 | into the record of the proceedings, all transcripts or other recordings 71 | of hearings and all orders, decisions and awards of the arbitral 72 | tribunal, subject only to the arbitral tribunal’s powers to take such 73 | measures as may be necessary to safeguard the integrity of the arbitral 74 | process pursuant to Articles 18, 33, 41 and 42 of the Rules; and (3) 75 | Article 26(6) of the Rules shall not apply. 76 | . Human Rights Laws. The Software shall not be used by any person or 77 | entity for any systems, activities, or other uses that violate any Human 78 | Rights Laws. "Human Rights Laws" means any applicable laws, 79 | regulations, or rules (collectively, "Laws") that protect human, 80 | civil, labor, privacy, political, environmental, security, economic, due 81 | process, or similar rights; provided, however, that such Laws are 82 | consistent and not in conflict with Human Rights Principles (a dispute 83 | over the consistency or a conflict between Laws and Human Rights 84 | Principles shall be determined by arbitration as stated above). Where 85 | the Human Rights Laws of more than one jurisdiction are applicable or in 86 | conflict with respect to the use of the Software, the Human Rights Laws 87 | that are most protective of the individuals or groups harmed shall 88 | apply. 89 | . Indemnity. Licensee shall hold harmless and indemnify Licensor (and 90 | any other contributor) against all losses, damages, liabilities, 91 | deficiencies, claims, actions, judgments, settlements, interest, awards, 92 | penalties, fines, costs, or expenses of whatever kind, including 93 | Licensor’s reasonable attorneys’ fees, arising out of or relating to 94 | Licensee’s use of the Software in violation of Human Rights Laws or 95 | Human Rights Principles. 96 | * Failure to Comply. Any failure of Licensee to act according to the 97 | terms and conditions of this License is both a breach of the License and 98 | an infringement of the intellectual property rights of the Licensor 99 | (subject to exceptions under Laws, e.g., fair use). In the event of a 100 | breach or infringement, the terms and conditions of this License may be 101 | enforced by Licensor under the Laws of any jurisdiction to which 102 | Licensee is subject. Licensee also agrees that the Licensor may enforce 103 | the terms and conditions of this License against Licensee through 104 | specific performance (or similar remedy under Laws) to the extent 105 | permitted by Laws. For clarity, except in the event of a breach of this 106 | License, infringement, or as otherwise stated in this License, Licensor 107 | may not terminate this License with Licensee. 108 | * Enforceability and Interpretation. If any term or provision of this 109 | License is determined to be invalid, illegal, or unenforceable by a 110 | court of competent jurisdiction, then such invalidity, illegality, or 111 | unenforceability shall not affect any other term or provision of this 112 | License or invalidate or render unenforceable such term or provision in 113 | any other jurisdiction; provided, however, subject to a court 114 | modification pursuant to the immediately following sentence, if any term 115 | or provision of this License pertaining to Human Rights Laws or Human 116 | Rights Principles is deemed invalid, illegal, or unenforceable against 117 | Licensee by a court of competent jurisdiction, all rights in the 118 | Software granted to Licensee shall be deemed null and void as between 119 | Licensor and Licensee. Upon a determination that any term or provision 120 | is invalid, illegal, or unenforceable, to the extent permitted by Laws, 121 | the court may modify this License to affect the original purpose that 122 | the Software be used in compliance with Human Rights Principles and 123 | Human Rights Laws as closely as possible. The language in this License 124 | shall be interpreted as to its fair meaning and not strictly for or 125 | against any party. 126 | * Disclaimer. TO THE FULL EXTENT ALLOWED BY LAW, THIS SOFTWARE COMES 127 | "AS IS," WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED, AND LICENSOR AND 128 | ANY OTHER CONTRIBUTOR SHALL NOT BE LIABLE TO ANYONE FOR ANY DAMAGES OR 129 | OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE 130 | OR THIS LICENSE, UNDER ANY KIND OF LEGAL CLAIM. 131 | 132 | This Hippocratic License is an link:https://ethicalsource.dev[Ethical Source license] and is offered 133 | for use by licensors and licensees at their own risk, on an "AS IS" basis, and with no warranties 134 | express or implied, to the maximum extent permitted by Laws. 135 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :toc: macro 2 | :toclevels: 5 3 | :figure-caption!: 4 | 5 | = Bashsmith 6 | 7 | Bashsmith is a project template for smithing new link:https://www.gnu.org/software/bash[Bash] 8 | shell-based projects based on best practices. This project is meant to be cloned and customized for 9 | your specific shell scripting needs giving you a foundation from which to get started faster than 10 | with an empty slate. 11 | 12 | toc::[] 13 | 14 | == Features 15 | 16 | * Provides default project structure for creating new Bash projects. 17 | * Provides default settings for making Bash scripts easier to develop and debug. 18 | 19 | == Requirements 20 | 21 | * link:https://www.gnu.org/software/bash[Bash] 22 | 23 | == Setup 24 | 25 | To install, run: 26 | 27 | [source,bash] 28 | ---- 29 | git clone https://github.com/bkuhlmann/bashsmith.git 30 | cd bashsmith 31 | git checkout 6.6.0 32 | ---- 33 | 34 | == Usage 35 | 36 | === File Structure 37 | 38 | All files located within this project provide the basic structure/blueprint for creating new Bash 39 | script projects. The structure is organized as follows: 40 | 41 | .... 42 | ├── CHANGES.adoc # The details of past version releases. 43 | ├── CODE_OF_CONDUCT.adoc # Guidelines for encouraging harassment-free contributions. 44 | ├── CONTRIBUTING.adoc # The details of how to contribute to the project. 45 | ├── LICENSE.adoc # The license and copyright legalities of the project. 46 | ├── README.adoc # The project overview, setup, usage, testing, etc. 47 | ├── bin # A folder for executable Bash scripts. 48 | │   └── run # The main run script (which loads the lib and settings). 49 | ├── lib # A folder for Bash functions and custom code. 50 | │   └── cli.sh # Provides CLI prompt options for the main `run` script. 51 | ├── settings # The global/project settings for easy manipulation/tweaking. 52 | │   └── main.sh # The global settings (set with safe defaults). 53 | .... 54 | 55 | === Template 56 | 57 | The following documents what each template option is: 58 | 59 | [source,bash] 60 | ---- 61 | # Exit, with error message, when attempting to use an undefined variable. 62 | # Alias: `set -u`. 63 | set -o nounset 64 | 65 | # Abort script at first error when a command exits with non-zero status. 66 | # Alias: `set -e`. 67 | set -o errexit 68 | 69 | # Return exit status of the last command in the pipe that returned a non-zero return value. 70 | set -o pipefail 71 | 72 | # Defines newlines and tabs as delimiters for splitting words and iterating arrays. 73 | IFS=$'\n\t' 74 | ---- 75 | 76 | === Debugging 77 | 78 | For debugging purposes, you can add the following option: 79 | 80 | [source,bash] 81 | ---- 82 | # Prints all executed commands. 83 | # Alias: `set -x`. 84 | set -o xtrace 85 | ---- 86 | 87 | The above is useful for debugging purposes but probably not something you want always enabled. 88 | 89 | 💡 For additional options, use `help set` to learn more. 90 | 91 | == Development 92 | 93 | To contribute, run: 94 | 95 | [source,bash] 96 | ---- 97 | git clone https://github.com/bkuhlmann/bashsmith.git 98 | cd bashsmith 99 | ---- 100 | 101 | == Tests 102 | 103 | Consider using link:https://github.com/sstephenson/bats[Bats]. 104 | 105 | == link:https://alchemists.io/policies/license[License] 106 | 107 | == link:https://alchemists.io/policies/security[Security] 108 | 109 | == link:https://alchemists.io/policies/code_of_conduct[Code of Conduct] 110 | 111 | == link:https://alchemists.io/policies/contributions[Contributions] 112 | 113 | == link:https://alchemists.io/policies/developer_certificate_of_origin[Developer Certificate of Origin] 114 | 115 | == link:https://alchemists.io/projects/bashsmith/versions[Versions] 116 | 117 | == link:https://alchemists.io/community[Community] 118 | 119 | == Credits 120 | 121 | Engineered by link:https://alchemists.io/team/brooke_kuhlmann[Brooke Kuhlmann]. 122 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "git/lint/rake/register" 4 | require "rubocop/rake_task" 5 | 6 | Git::Lint::Rake::Register.call 7 | RuboCop::RakeTask.new 8 | 9 | desc "Run code quality checks" 10 | task quality: %i[git_lint rubocop] 11 | 12 | task default: :quality 13 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "bundler/setup" 5 | 6 | load Gem.bin_path "rake", "rake" 7 | -------------------------------------------------------------------------------- /bin/run: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # DESCRIPTION 4 | # Executes the script. 5 | 6 | # SETTINGS 7 | source settings/main.sh 8 | 9 | # LIBRARY 10 | source lib/cli.sh 11 | 12 | # EXECUTION 13 | while true; do 14 | if [[ $# == 0 ]]; then 15 | printf "\nUsage: run OPTION\n" 16 | printf "\nScript Options:\n" 17 | printf " q: Quit/Exit.\n\n" 18 | read -r -p "Enter selection: " response 19 | printf "\n" 20 | process_option "$response" 21 | else 22 | process_option "$1" 23 | fi 24 | 25 | break 26 | done 27 | -------------------------------------------------------------------------------- /lib/cli.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # DESCRIPTION 4 | # Defines command line prompt options. 5 | 6 | # Process option selection. 7 | # Parameters: 8 | # $1 = The option to process. 9 | process_option() { 10 | case $1 in 11 | 'q');; 12 | *) 13 | printf "ERROR: Invalid option.\n";; 14 | esac 15 | } 16 | export -f process_option 17 | -------------------------------------------------------------------------------- /settings/main.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | set -o nounset 4 | set -o errexit 5 | set -o pipefail 6 | IFS=$'\n\t' 7 | --------------------------------------------------------------------------------