Last active
March 22, 2023 10:10
-
-
Save jgornick/528ab6a181204f0d5b02 to your computer and use it in GitHub Desktop.
Bash: Helper Functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Returns a UTC timestamp of the current date/time. | |
# Can provide an optional format that matches date(1) format | |
now() { | |
local format="${1:-"%s"}" | |
echo -n "$(date -u +"$format")" | |
} | |
# Extract the first element of a list. | |
head() { | |
echo -n "${@:1:1}" | |
} | |
# Extract the last element of a list. | |
last() { | |
echo -n "${@:(-1)}" | |
} | |
# Return all the elements of a list except the last one. | |
init() { | |
echo -n "${@:1:(($#-1))}" | |
} | |
# Extract the elements after the head of a list. | |
tail() { | |
echo -n "${@:2}" | |
} | |
# Retry a function | |
# @param $1 number Retry Times | |
# @param $2 number Retry Wait | |
# @param $@ mixed Function and arguments | |
retry() { | |
times=$1; shift; | |
wait=$1; shift; | |
until "$@"; do | |
(( --times <= 0 )) && return 1 | |
sleep $wait | |
done | |
} | |
# Negate the provided function return code. | |
not() { | |
! "$@" | |
} | |
# Hide all stdout and stderr from the provided function | |
quiet() { | |
"$@" >& /dev/null | |
} | |
# Creates a list (newline) from the specified arguments | |
list() { | |
printf %s\\n "$@" | |
} | |
# Creates a list (no-newline) from the specified arguments | |
unlist() { | |
echo -n "$@" | |
} | |
# Composes the two specified functions and applies any arguments to the second. | |
# @param name The name of the new composed function | |
# @param f1 The first (outer) function | |
# @param f2 The second (inner) function | |
compose() { | |
name=$1; shift | |
f1=$1; shift | |
f2=$1; shift | |
eval "$name() { $f1 \$($f2 \$*); }" | |
echo -n $name | |
} | |
# Creates a new function with the arguments applied to the specified function. | |
# @param name The name of the new function | |
# @param func The function to partially apply arguments | |
# @param args The arguments to apply to the function | |
partial() { | |
local name=$1; shift | |
local func=$1; shift | |
local args=$* | |
eval "$name() { $func $args \$*; }" | |
echo -n $name | |
} | |
map() { | |
local collection=( $(init "$@") ) | |
local iteratee=$(last "$@") | |
local result=() | |
local value | |
local ret | |
for i in "${collection[@]}"; do | |
value="$($iteratee "$i")" | |
ret=$? | |
if (( ret != 0 )); then | |
echo -n "$value" | |
return $ret | |
fi | |
result+=( "$value" ) | |
done | |
list "${result[@]}" | |
} | |
isInt() { | |
[[ $1 =~ ^-?[0-9]+$ ]] | |
} | |
indexOf() { | |
local collection=( $(init "$@") ) | |
local value=$(last "$@") | |
for i in "${!collection[@]}"; do | |
if [[ "${collection[$i]}" == "${value}" ]]; then | |
echo -n "$i" | |
return 0 | |
fi | |
done | |
echo -n "-1" | |
return 1 | |
} | |
min() { | |
local result="$1" | |
for i in "$@"; do | |
result=$(( i < result ? i : result )) | |
done | |
echo -n "$result" | |
} | |
max() { | |
local result="$1" | |
for i in "$@"; do | |
result=$(( i > result ? i : result )) | |
done | |
echo -n "$result" | |
} | |
extractNumber() { | |
echo -n "$(echo "$1" | sed 's/[^0-9]//g')" | |
} | |
extractString() { | |
echo -n "$(echo "$1" | sed 's/[0-9]//g')" | |
} | |
# Similar to timeout(1) except that this will call a provided iteratee argument if specified | |
# for each iteration to check the command | |
# @param mixed cmd Function and arguments | |
# @param number duration Timeout duration in seconds | |
# @param function [iteratee] Optional function to call each check iteration | |
timeout() ( | |
local args=( "$@" ) | |
local cmd | |
local iteratee | |
local duration=$(last "${args[@]}") | |
if ! isInt "$duration"; then | |
# The last argument is a function (iteratee) | |
iteratee="$duration" | |
# Pop the iteratee off the args | |
args=( $(init "${args[@]}") ) | |
# Set the duration to the last of the args | |
duration=$(last "${args[@]}") | |
fi | |
if ! (( duration > 0 )); then | |
echo "Missing duration argument" | |
return 1 | |
fi | |
# Pop the duration off the args | |
args=( $(init "${args[@]}") ) | |
cmd=( "${args[@]}" ) | |
"${cmd[@]}" & | |
local cmdPid=$! | |
local start="$(now)" | |
while (( $(now) - start < duration )); do | |
if kill -0 "$cmdPid" >& /dev/null; then | |
[[ $iteratee ]] && $iteratee "$cmdPid" | |
else | |
wait "$cmdPid" >& /dev/null | |
return $? | |
fi | |
sleep 1 | |
done | |
if ! kill "$cmdPid" >& /dev/null; then | |
kill -9 "$cmdPid" >& /dev/null | |
return 9 | |
fi | |
return 1 | |
) | |
lowerCase() { | |
if (( $# )); then printf %s\\n "$*" | "${FUNCNAME[0]}"; return; fi | |
sed -re 's/./\L&/g' | |
} | |
lowerFirst() { | |
if (( $# )); then printf %s\\n "$*" | "${FUNCNAME[0]}"; return; fi | |
sed -re 's/([a-zA-Z])(.*)/\L\1\E\2/g' | |
} | |
upperCase() { | |
if (( $# )); then printf %s\\n "$*" | "${FUNCNAME[0]}"; return; fi | |
sed -re 's/./\U&/g' | |
} | |
upperFirst() { | |
if (( $# )); then printf %s\\n "$*" | "${FUNCNAME[0]}"; return; fi | |
sed -re 's/([a-zA-Z])(.*)/\U\1\E\2/g' | |
} | |
capitalize() { | |
if (( $# )); then printf %s\\n "$*" | "${FUNCNAME[0]}"; return; fi | |
sed -re 's/([a-zA-Z])(.*)/\U\1\L\2/g' | |
} | |
camelCase() { | |
if (( $# )); then printf %s\\n "$*" | "${FUNCNAME[0]}"; return; fi | |
sed -re 's/[-_ ]([a-zA-Z0-9])/\u\1/g' \ | |
| sed -re 's/([a-zA-Z])(.*)/\L\1\E\2/g' | |
} | |
kebabCase() { | |
if (( $# )); then printf %s\\n "$*" | "${FUNCNAME[0]}"; return; fi | |
sed -re 's/[_ ]+/-/g' \ | |
| sed -re 's/([A-Z])/-\1/g' \ | |
| sed -re 's/-+/-/g' \ | |
| sed -re 's/./\L&/g' | |
} | |
snakeCase() { | |
if (( $# )); then printf %s\\n "$*" | "${FUNCNAME[0]}"; return; fi | |
sed -re 's/[- ]+/_/g' \ | |
| sed -re 's/([A-Z])/_\1/g' \ | |
| sed -re 's/_+/_/g' \ | |
| sed -re 's/./\L&/g' | |
} | |
titleCase() { | |
if (( $# )); then printf %s\\n "$*" | "${FUNCNAME[0]}"; return; fi | |
sed -re 's/[-_]+/ /g' \ | |
| sed -re 's/^[ ]+//' \ | |
| sed -re 's/[ ]+$//' \ | |
| sed -re 's/.*/\L&/' \ | |
| sed -re 's/[[:graph:]]*/\u&/g' | |
} | |
array-includes () { | |
local array=($(init "$@")) | |
local target=$(last "$@") | |
for e in "${array[@]}"; do | |
[[ $e == $target ]] && return 0 | |
done | |
return 1 | |
} | |
run-command-on-ip () { | |
local ip="${1:?Missing IP address}"; shift | |
ssh \ | |
-o UserKnownHostsFile=/dev/null \ | |
-o StrictHostKeyChecking=no \ | |
-o PasswordAuthentication=no \ | |
-o IdentitiesOnly=yes \ | |
-o BatchMode=yes \ | |
-o ConnectTimeout=1 \ | |
-o ConnectionAttempts=1 \ | |
-q \ | |
"$ip" \ | |
"$@" | |
} | |
run-script-on-ip () { | |
local ip="${1:?Missing IP address}"; shift | |
local script="${1:?Missing script}"; shift | |
ssh \ | |
-o UserKnownHostsFile=/dev/null \ | |
-o StrictHostKeyChecking=no \ | |
-o PasswordAuthentication=no \ | |
-o IdentitiesOnly=yes \ | |
-o BatchMode=yes \ | |
-o ConnectTimeout=1 \ | |
-o ConnectionAttempts=1 \ | |
-q \ | |
"$ip" \ | |
"sudo bash -s" < "$script" | |
} | |
copy-file-to-ip () { | |
local target="${1:?"Missing target address:path"}" | |
local file="${2:?Missing file}" | |
scp \ | |
-o UserKnownHostsFile=/dev/null \ | |
-o StrictHostKeyChecking=no \ | |
-o PasswordAuthentication=no \ | |
-o IdentitiesOnly=yes \ | |
-o BatchMode=yes \ | |
-o ConnectTimeout=1 \ | |
-o ConnectionAttempts=1 \ | |
-q \ | |
"$file" "$target" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment