├── README.md ├── docs └── resources │ └── preview.gif └── template.sh /README.md: -------------------------------------------------------------------------------- 1 | # Bash Command Template 2 | 3 | A bash command starter template with a handful of nice-to-have utilities. 4 | 5 | ![Preview of the template in action](docs/resources/preview.gif) 6 | 7 | ## Usage 8 | 9 | After making a copy of `template.sh` you can start modifying the `cleanup` and `main` functions to fit your needs. 10 | -------------------------------------------------------------------------------- /docs/resources/preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sixlive/bash-command-template/7caf0075084a4a9c7a1100fefa874949de06aa48/docs/resources/preview.gif -------------------------------------------------------------------------------- /template.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Setup 4 | # --------------------------------------------------------------- 5 | set -o errexit 6 | set -o nounset 7 | set -o pipefail 8 | 9 | trap cleanup SIGINT SIGTERM ERR EXIT 10 | 11 | if [[ -n "${TRACE-}" ]]; then 12 | set -o xtrace 13 | fi 14 | 15 | # Utilities 16 | # --------------------------------------------------------------- 17 | 18 | # Print a message to stdout 19 | # Usage: prntc 20 | # Example: prntc "red" "This is a red message" 21 | prntc() { 22 | local color="$1" 23 | local content="${2:-}" 24 | 25 | # Color mappings 26 | local default="\033[0m" 27 | local red="\033[31m" 28 | local green="\033[0;32m" 29 | local yellow="\033[0;33m" 30 | local magenta="\033[0;35m" 31 | local cyan="\033[0;36m" 32 | 33 | if [[ -z "${!color-}" ]]; then 34 | content="$color" 35 | color="default" 36 | fi 37 | 38 | printf "${!color}$content$default" 39 | } 40 | 41 | # Print a message to stdout with a newline 42 | # Usage: prntcn 43 | # Example: prntcn "red" "This is a red message" 44 | prntcn() { 45 | local color="$1" 46 | local content="${2:-}" 47 | 48 | printf "$(prntc "$color" "$content") \r\n" 49 | } 50 | 51 | # Print a message to stdout with a newline 52 | # Usage: prntTitle 53 | # Example: prntTitle "This is a title" 54 | prntTitle () { 55 | prntDivider 56 | prntcn "$1" 57 | prntDivider 58 | } 59 | 60 | # Print a divider 61 | # Usage: prntDivider 62 | # Example: prntDivider "This is a divider" 63 | # Example: prntDivider 64 | prntDivider () { 65 | local divider; 66 | local content="${1:-}" 67 | divider=$(printf -- '-%.0s' {1..60}) 68 | 69 | # if content is empty then just print the divider 70 | if [[ -z "$content" ]]; then 71 | prntcn "cyan" "$divider" 72 | return 73 | fi 74 | 75 | local contentLength=${#content} 76 | local dividerLength=${#divider} 77 | 78 | if [[ "$contentLength" -gt "$dividerLength" ]]; then 79 | prntcn "red" "Content is longer than the divider" 80 | exit 1 81 | fi 82 | 83 | content="-- $content " 84 | 85 | local diff=$((dividerLength - ${#content})) 86 | 87 | printf "\r\n" 88 | prntc "cyan" "$content" 89 | prntcn "cyan" "${divider:0:$diff}" 90 | } 91 | 92 | # Prompt the user to confirm 93 | # 94 | # @param variable The to assign the result to 95 | # @param string The question to prompt the user with 96 | # @param string The prompt to show the user 97 | # @param string The regex to match the response against 98 | # 99 | # Example: 100 | # confirm confirmation "Are you sure?" "yes/NO" "(yes)" 101 | confirm() { 102 | local confirmExport="$1" 103 | local export=false 104 | local question="${2:-"Are you sure?"}" 105 | local confirmPrompt="${3:-"y/N"}" 106 | local confirmMatcher="${4:-"(y)"}" 107 | 108 | question+=$(prntc "cyan" " [$confirmPrompt] ") 109 | 110 | prntc "magenta" "$question " 111 | 112 | # read response 113 | response=$(read -e line; echo "$line") 114 | 115 | shopt -s nocasematch 116 | 117 | if [[ $response =~ $confirmMatcher ]]; then 118 | export=true 119 | else 120 | export=false 121 | fi 122 | 123 | shopt -u nocasematch 124 | 125 | eval "$confirmExport=$export" 126 | } 127 | 128 | # Show a spinner while running a command 129 | # @param string The label to show next to the spinner 130 | # @param string The command to run 131 | # 132 | # Example: 133 | # spinner "Pinging google" ping -c 3 google.com 134 | spinner () { 135 | function shutdown() { 136 | tput cnorm # reset cursor 137 | } 138 | 139 | trap shutdown EXIT 140 | 141 | function cursorBack() { 142 | printf "\r"; printf ' %0.s' {0..20} 143 | } 144 | 145 | function spin() { 146 | local LC_CTYPE=C 147 | 148 | local pid=$2 149 | local spin='⣾⣽⣻⢿⡿⣟⣯⣷' 150 | local charwidth=3 151 | local i=0 152 | local label="$1" 153 | local length=(${#label} + $charwidth + 1) 154 | 155 | tput civis # cursor invisible 156 | while kill -0 $pid 2>/dev/null; do 157 | local i=$(((i + $charwidth) % ${#spin})) 158 | prntc "cyan" "${spin:$i:$charwidth} $label" 159 | printf "\r"; 160 | printf '%0.s' {0..$length} 161 | 162 | sleep .1 163 | done 164 | 165 | tput cnorm 166 | wait $pid 167 | 168 | prntcn "cyan" "✓ $label" 169 | 170 | return $? 171 | } 172 | 173 | ("${@:2}") >/dev/null & 174 | 175 | spin "$1" $! 176 | } 177 | 178 | # App Code 179 | # --------------------------------------------------------------- 180 | 181 | # This method is referenced in the trap above 182 | cleanup () { 183 | trap - SIGINT SIGTERM ERR EXIT 184 | printf "\r\n" # ensure we have a new line if an error occured 185 | 186 | prntDivider "Cleanup" 187 | prntcn "green" "Done!" 188 | } 189 | 190 | # Parse the command line arguments 191 | # Usage: parseArgs "$@" 192 | # Example: parseArgs "$@" 193 | parseArgs() { 194 | while getopts i:o: flag; do 195 | case "${flag}" in 196 | i) 197 | input="${OPTARG}" 198 | ;; 199 | o) 200 | output="${OPTARG}" 201 | ;; 202 | esac 203 | done 204 | } 205 | 206 | # Main function that is called when the script executes 207 | main() { 208 | prntTitle "Party Time 🎉" 209 | 210 | parseArgs "$@" 211 | prntDivider "Args" 212 | prntc "magenta" "Input Arg: " 213 | prntcn "cyan" "${input:-"No input provided"}" 214 | prntc "magenta" "Output Arg: " 215 | prntcn "cyan" "${output-"No input provided"}" 216 | 217 | prntDivider "Party pre-game" 218 | 219 | local confirmation 220 | confirm confirmation "Are you ready to party?" "yes/NO" "(yes)" 221 | 222 | if ! $confirmation; then 223 | prntcn "red" "Party cancelled 😢" 224 | exit 1 225 | fi 226 | 227 | spinner "Getting the party ready" sleep 2 228 | prntcn "green" "LEEEEEEETS GOOOOOOOOOO 🥳" 229 | 230 | cleanup 231 | } 232 | 233 | main "$@" 234 | --------------------------------------------------------------------------------