Skip to content

Instantly share code, notes, and snippets.

@benc-uk
Last active August 12, 2024 09:40
Show Gist options
  • Save benc-uk/54b663b7e2443d5fbfeaa1b30391436b to your computer and use it in GitHub Desktop.
Save benc-uk/54b663b7e2443d5fbfeaa1b30391436b to your computer and use it in GitHub Desktop.
Bash snippets

Bash scripts and snippets

#
# Common recipes and tricks
#
# Check for missing commands & tools
which foo > /dev/null || { echo -e "๐Ÿ’ฅ Error! Command foo not installed"; exit 1; }
# Single variable
[[ -z "$SOMEVAR" ]] && { echo "๐Ÿ’ฅ Error! Required variable SOMEVAR is not set!"; exit 1; }
# List of many variables (make sure `set -u` is NOT used)
for varName in REQUIRED_VAR ALSO_REQUIRED SO_IS_THIS; do
varVal=$(eval echo "\${$varName}")
[[ -z $varVal ]] && { echo "๐Ÿ’ฅ Error! Required variable '$varName' is not set!"; varUnset=true; }
done
[[ $varUnset ]] && exit 1
#!/bin/bash
NAME="cert"
DOMAIN="localhost"
#DOMAIN="myapp.benco.io"
IP="12.34.56.78"
DAYS="3650"
# Create a self-signed cert with a single command, with SNI/SAN
openssl req -x509 -newkey rsa:4096 -sha256 -days "$DAYS" -nodes \
-keyout "$NAME".key -out "$NAME".pem -subj "/CN=$DOMAIN" \
-addext "subjectAltName=DNS:$DOMAIN,IP:$IP"
# Convert to a PKCS12 file, you might want it in that format I dunno ยฏ\_(ใƒ„)_/ยฏ
#openssl pkcs12 -export -out "$NAME".p12 -inkey "$NAME".key -in "$NAME".pem

Using mkcert with WSL

Using mkcert with WSL can be a little tricky as it creates a root CA for you and installs it in the relevant place for the OS to be trusted. If you run this in WSL it will result in your browser over on the Windows side still not trusting the certs you create with mkcert.

This is a workaround / solution:

  • Install root CA: mkcert -install
  • Convert the root CA to PKCS12, run: openssl pkcs12 -export -out rootCA.pfx -inkey $(mkcert -CAROOT)/rootCA-key.pem -in $(mkcert -CAROOT)/rootCA.pem
    • Specify no password, just hit enter
  • Run explorer.exe .
  • In Windows Explorer; double click the rootCA.pfx file to import the certificate
    • Pick the "Place all certificates in the following store" option
    • Select "Trusted Root Certification Authorities"
  • Run: mkcert localhost or any other name (e.g. mkcert foo.example.net) to generate a certificate and use certs with whatever server/software/SDK as normal
  • Delete the rootCA.pfx file
#!/bin/bash
host=localhost
port=8080
maxTries=3
sleep=5
tries=0
while ! nc -z $host $port; do
echo "Waiting ${sleep}s for $host:$port to accept connections"
sleep $sleep
tries=$((tries+1))
if [ $tries -ge $maxTries ]; then
echo "FAILED: Unable to connect to the $host:$port after $maxTries tries"
exit 1
fi
done
echo "Port $port is available, $host is online"
#!/bin/bash
# Quickly create a new CSR with a new key
DOMAIN=${1:-"blah.example.net"}
FILE_BASENAME=${2:-"example_net"}
LOCATION="London"
COUNTRY="GB"
ORG="Damage Inc."
openssl req -new -newkey rsa:2048 -nodes \
-out "${FILE_BASENAME}.csr" \
-keyout "${FILE_BASENAME}.key" \
-subj "/C=${COUNTRY}/ST=/L=${LOCATION}/O=${ORG}/CN=${DOMAIN}"
#!/usr/bin/env bash
set -euo pipefail
if [[ "${TRACE-0}" == "1" ]]; then set -o xtrace; fi
if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then
echo -e "Usage: $(basename "$0") some-args\nBlah blah change this text"
exit
fi
cd "$(dirname "$0")"
# Rest of the script
#!/bin/bash
declare count=0 maxTime=30
[[ $# < 2 ]] && { echo "๐Ÿ’ฌ Pass URL and content check as args"; exit 1; }
while (( $count < $maxTime )); do
# Remove the grep if you don't need content checking
curl -sSL $1 | grep $2
if [ $? -eq 0 ]; then
echo "๐Ÿ˜ URL check passed, content match found!"
exit 0
else
echo "โŒš URL check failed, trying again in 1 second"
sleep 1
((count=count+1))
fi
done
echo "๐Ÿ’ฅ Giving up after $maxTime seconds, check failed!"
exit 1
#!/bin/bash
declare -i time=60
declare -i delay=5
declare -i count=5
declare -i okCount=0
declare -i elapsed=0
declare isUp="false"
# Display usage
usage(){
echo -e "\e[32mโ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ"
echo -e "โ”‚ ๐ŸŒ \e[94murl-check.sh \e[96mCheck URL endpoint for HTTP responses ๐Ÿš€\e[32m โ”‚"
echo -e "โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ"
echo -e "\n\e[95mParameters:\e[37m"
echo -e " -u, --url \e[33mURL to check (required)\e[37m"
echo -e " [-t, --time] \e[33mMaximum number of seconds to poll for \e[92m(default: 60)\e[37m"
echo -e " [-d, --delay] \e[33mDelay in seconds between requests \e[92m(default: 5)\e[37m"
echo -e " [-c, --count] \e[33mHow many successes to receive before exiting \e[92m(default: 5)\e[37m"
echo -e " [-s, --search] \e[33mOptional content check, grep for this string in HTTP body \e[92m(default: none)\e[37m"
echo -e " [-h, --help] \e[33mShow this help text\e[37m"
}
if ! OPTS=$(getopt -o u:t:d:c:s:h --long url:,time:,delay:,count:,search:,help -n 'parse-options' -- "$@"); then echo "Failed parsing options." >&2 ; usage; exit 1 ; fi
eval set -- "$OPTS"
while true; do
case "$1" in
-u | --url ) url="$2"; shift; shift;;
-t | --time ) time="$2"; shift; shift;;
-d | --delay ) delay="$2"; shift; shift;;
-c | --count ) count="$2"; shift; shift;;
-s | --search ) search="$2"; shift; shift;;
-h | --help ) HELP=true; shift ;;
-- ) shift; break ;;
* ) break ;;
esac
done
if [[ ${HELP} = true ]] || [ -z "${url}" ]; then
usage
exit 0
fi
# Check for impossible parameter combination ie. too many checks and delays in given time limit
if (( delay * count > time)); then
echo -e "\e[31m### Error! The time ($time) provided is too short given the delay ($delay) and count ($count)\e[0m"
exit 1
fi
echo -e "\n\e[36m### Polling \e[33m$url\e[36m for ${time}s, to get $count OK results, with a ${delay}s delay\e[0m\n"
# Generate tmp filename
tmpfile=$(echo "$url" | md5sum)
# Main loop
while [ "$isUp" != "true" ]
do
# Break out of loop if max time has elapsed
if (( elapsed >= time )); then break; fi
timestamp=$(date "+%Y/%m/%d %H:%M:%S")
# Main CURL test, output to file and return http_code
urlstatus=$(curl -o "/tmp/$tmpfile" --silent --write-out '%{http_code}' "$url")
if [ "$urlstatus" -eq 000 ]; then
# Code 000 means DNS, network error or malformed URL
msg="\e[95mSite not found or other error"
else
if (( urlstatus >= 200 )) && (( urlstatus < 300 )); then
# Check returned content with grep if check specified
if [ -n "$search" ]; then
# Only count as a success if string grep passed
if grep -q "$search" "/tmp/$tmpfile"; then
(( okCount=okCount + 1 ))
msg="โœ… \e[32m$urlstatus ๐Ÿ” Content check for '$search' passed"
else
msg="โŒ \e[91m$urlstatus ๐Ÿ” Content check for '$search' failed"
fi
else
# Good status code
((okCount=okCount + 1))
msg="โœ… \e[32m$urlstatus "
fi
if (( okCount >= count )); then isUp="true"; fi
else
# Bad status code
msg="โŒ \e[91m$urlstatus "
fi
fi
# Output message + timestamp then delay
echo -e "### $timestamp: $msg\e[0m"
# if isUp false then delay
if [ "$isUp" != "true" ]; then sleep "$delay"; fi
((elapsed=elapsed + delay))
done
rm "/tmp/$tmpfile" > /dev/null 2>&1
# Final result check
if [ "$isUp" == "true" ]; then
echo -e "\n\e[32m### Result: $url is UP! ๐Ÿคฉ\e[0m"
exit 0
else
echo -e "\n\e[91m### Result: $url is DOWN! ๐Ÿ˜ข\e[0m"
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment