diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..02b486a --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.bak +*.backup +*.gho +*.ori +*.orig +*.tmp +*.swp diff --git a/README.md b/README.md index ac91938..4086d5e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,30 @@ -# bash-helper +## bash-helper-script + +A collection of helper functions to be used within your bash script. + +### Download via git clone +``` +git clone https://git.x-files.dk/bash/bash-helper.git +``` +> **NOTE** +> The helper script should reside in the same directory as your main bash script. + +### How to source the script within your main bash script. +```bash +#!/usr/bin/env bash + +source "$(dirname "$0")/helper" + +# main bash script goes below this line +``` + +### Guide and howto's examples can be found here. +Bash helper function howto [\[link\]](https://wiki.x-files.dk/doku.php?id=linux:bash_helper_howto) + +### More guides +More guides can be found on [\[wiki.x-files.dk\]](https://wiki.x-files.dk) + +### Last tested +August 20th 2025 on Ubuntu 24.04. + diff --git a/helper b/helper new file mode 100644 index 0000000..527b2dc --- /dev/null +++ b/helper @@ -0,0 +1,221 @@ +##################################################################### +# First Created: 15082025 Author: Allan Desc: +# supplies multiple functions that can help in creating bash scripts. +# +# For documentation and examples please see this link. +# +# https://wiki.x-files.dk/doku.php?id=linux:bash_helper_howto +# +# Download from git use this link. +# +# https://git.x-files.dk/bash/bash-helper-script +# +##################################################################### + +# +# Are we root if not die +# +must_be_root() { + local required="$1" + + if [[ "$required" == "yes" ]]; then + if [[ $UID -ne 0 ]]; then + printf "\nThis script must be run as root or use sudo\n\n" + exit 1 + fi + fi +} + +# +# Are we in the right directory if not die +# +must_be_in_dir() { + local required_dir="$1" + if [[ "${PWD##*/}" != "$required_dir" ]]; then + printf "\nWrong directory! This script must be run from the directory '%s'\n\n" "$required_dir" + exit 1 + fi +} + +# +# Output x characters +# +line() { printf "%0.s$1" $(seq 1 $2); printf '\n'; } + +# +# Checks if a service is running or not and react accordingly +# + +# +# Service(s) must be running +# +must_be_running() { + local bad_services=() + for service in "$@"; do + if [[ "$(systemctl is-active "$service")" != "active" ]]; then + bad_services+=("$service") + fi + done + + if (( ${#bad_services[@]} > 0 )); then + echo "The following service(s) appear not to be running, cannot continue..." + for svc in "${bad_services[@]}"; do + echo " - $svc" + done + exit 1 + fi +} + +# +# Service(s) must not be running +# +must_not_be_running() { + local bad_services=() + for service in "$@"; do + if [[ "$(systemctl is-active "$service")" == "active" ]]; then + bad_services+=("$service") + fi + done + + if (( ${#bad_services[@]} > 0 )); then + echo "The following service(s) appear already to be running, cannot continue..." + for svc in "${bad_services[@]}"; do + echo " - $svc" + done + exit 1 + fi +} + +# +# Detect input mode: "flags" or "positional" this will detect whether $1 or getopts is beeing used. +# +detect_mode() { + for arg in "$@"; do + if [[ "$arg" == -* ]]; then + echo "flags" + return + fi + done + echo "positional" +} + +# +# Print usage dynamically (adapts to mode) +# +usage() { + local mode + mode=$(detect_mode "$@") + + printf "Usage: %s " "$0" + + if [[ $mode == "flags" ]]; then + printf "[options]\n" + for flag in "${flags[@]}"; do + short="${flag%%:*}" + rest="${flag#*:}" + desc="${rest#*:}" + desc="${desc%%:*}" + printf " -%s %s\n" "$short" "$desc" + done + printf " -h Show help\n\n" + + printf "Example:\n" + example="$0" + for flag in "${flags[@]}"; do + short="${flag%%:*}" + rest="${flag#*:}" # remove short + rest="${rest#*:}" # remove var + desc="${rest%%:*}" # description + rest="${rest#*:}" + sample="${rest%%:*}" + example+=" -$short ${sample:-$desc}" + done + printf "%s\n\n" "$example" + + else + # positional usage + for flag in "${flags[@]}"; do + rest="${flag#*:}" + var="${rest%%:*}" + rest="${rest#*:}" + desc="${rest%%:*}" + rest="${rest#*:}" + sample="${rest%%:*}" + required="${flag##*:}" + + if [[ "$required" == "true" ]]; then + printf "<%s> " "$desc" + else + printf "[%s] " "$desc" + fi + done + printf "\n\n" + + printf "Example:\n" + example="$0" + for flag in "${flags[@]}"; do + rest="${flag#*:}" # remove short + rest="${rest#*:}" # remove var + desc="${rest%%:*}" + rest="${rest#*:}" + sample="${rest%%:*}" + example+=" ${sample:-$desc}" + done + printf "%s\n\n" "$example" + fi +} + +# +# Validate required input (works in both modes) +# +validate_input() { + local mode + mode=$(detect_mode "$@") + local missing=false + local i=1 + + for flag in "${flags[@]}"; do + short="${flag%%:*}" + rest="${flag#*:}" + var="${rest%%:*}" + rest="${rest#*:}" + desc="${rest%%:*}" + rest="${rest#*:}" + sample="${rest%%:*}" + required="${flag##*:}" + + value="${!var}" + + if [[ -z "$value" && $mode == "positional" ]]; then + value="${!i}" + if [[ -n "$value" ]]; then + printf -v "$var" '%s' "$value" + fi + fi + + if [[ "$required" == "true" && -z "${!var}" ]]; then + printf "Error! %s is empty.\n" "$desc" + missing=true + fi + ((i++)) + done + + if [[ $missing == true ]]; then + printf "\n" + usage "$@" + exit 1 + fi +} + +# +# git clone if repo does not exist +# +git_clone_if_missing() { + local repo="$1" + local target_dir="$2" + local branch="${3:-main}" + + [[ -d "$target_dir/.git" ]] && return + echo "Cloning repository $repo into $target_dir..." + git clone --quiet --branch "$branch" "$repo" "$target_dir" +}