Created
September 11, 2024 19:22
-
-
Save ryancdotorg/dc368d1712ca067c28c2e8afad8922ff to your computer and use it in GitHub Desktop.
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/sh /dev/null | |
# vim: ft=bash: | |
__pat_safe() { expr "${1-}" : '[^[*!?:]*$' > /dev/null; } | |
if [ -z "${BASH_VERSION:-}" ]; then | |
# posix shells can't do variable indirection or pattern substitution | |
# directly, so we need to use eval and assorted commands | |
# https://stackoverflow.com/a/36235741/370695 | |
__var_safe() { expr "${1-}" : '[[:alpha:]_][[:alnum:]_]*$' > /dev/null; } | |
pathlist_append() { | |
if __var_safe "${1-}" && [ -d "${2-}" ]; then | |
eval "export ${1}=\"\${${1}:+\$${1}:}\$2\"" | |
fi | |
} | |
pathlist_prepend() { | |
if __var_safe "${1-}" && [ -d "${2-}" ]; then | |
eval "export ${1}=\"\$2\${${1}:+:\$${1}}\"" | |
fi | |
} | |
pathlist_has() { | |
if __var_safe "${1-}" && __pat_safe "${2-}"; then | |
local SAFE_DIR="$(printf '%s' "${2}" | sed 's/[$.*[\^]/\\&/g')" | |
eval "printf '%s\\n' \"\${${1}}\"" | grep "\\(:\\|^\\)${SAFE_DIR}\\(:\\|$\\)" > /dev/null | |
return $? | |
fi | |
return 1 | |
} | |
pathlist_remove() { | |
if __var_safe "${1-}" && __pat_safe "${2-}"; then | |
#local NEW_VALUE="$(eval printf '%s' \"\${${1}}\" | awk -v REM="${2}" -v RS=: -v ORS=: '$0 != REM' | sed 's/:$//')" | |
# adapted from https://www.linuxjournal.com/content/removing-duplicate-path-entries | |
local NEW_VALUE="$(eval printf '%s' \"\${${1}}\" | awk -v REM="${2}" -v RS=: '($0 != REM) {a[$0]; printf("%s%s", length(a) > 1 ? ":" : "", $0)}')" | |
eval "export ${1}=\"${NEW_VALUE}\"" | |
fi | |
} | |
pathlist_dedupe() { | |
if __var_safe "${1-}"; then | |
local NEW_VALUE="$(eval printf '%s' \"\${${1}}\" | awk -v RS=: '!($0 in a) {a[$0]; printf("%s%s", length(a) > 1 ? ":" : "", $0)}')" | |
eval "export ${1}=\"${NEW_VALUE}\"" | |
fi | |
} | |
else | |
# bash has enough functionality that everything can be done with builtins | |
pathlist_append() { [ -n "$1" -a -d "$2" ] && export "$1"="${!1:+${!1}:}$2"; } | |
pathlist_prepend() { [ -n "$1" -a -d "$2" ] && export "$1"="$2${!1:+:${!1}}"; } | |
pathlist_has() { | |
if [ -n "$1" ] && __pat_safe "${2-}"; then | |
if [ "${!1}" = "$2" ]; then # exact match | |
return 0 | |
else # try to remove the path component... | |
local __VALUE="${!1}" | |
local __LENGTH="${#__VALUE}" | |
__VALUE="${__VALUE//":$2:"/":"}" | |
__VALUE="${__VALUE/#"$2:"/}" | |
__VALUE="${__VALUE/%":$2"/}" | |
# ...and check whether the length changed | |
[ "${#__VALUE}" -ne ${__LENGTH} ] && return 0 | |
fi | |
#expr "${!1}" : "$(printf '%s' "$2" | sed 's/[$.*[\^]/\\&/g;s/\(.*\)/\\(\1:.\\+\\|.\\+:\1:.\\+\\|\1$\\|.\\+:\1$\\)/')" > /dev/null | |
#return $? | |
fi | |
return 1 | |
} | |
pathlist_remove() { | |
# https://stackoverflow.com/a/19587970/370695 | |
if [ -n "$1" ] && __pat_safe "${2-}"; then | |
local __VALUE="${!1}" | |
local __LENGTH="${#__VALUE}" | |
while :; do # remove from the middle until nothing happens | |
__VALUE="${__VALUE//":$2:"/":"}" | |
[ ${#__VALUE} -eq ${__LENGTH} ] && break | |
__LENGTH="${#__VALUE}" | |
done | |
__VALUE="${__VALUE/#"$2:"/}" | |
__VALUE="${__VALUE/%":$2"/}" | |
if [ "${__VALUE}" = "$2" ]; then | |
export "$1"="" | |
else | |
export "$1"="${__VALUE}" | |
fi | |
fi | |
} | |
pathlist_dedupe() { | |
local -A __KEYS | |
local -a __LIST | |
local __VALUE | |
readarray -t __LIST <<< "${!1//":"/$'\n'}" | |
for ENTRY in "${__LIST[@]}"; do | |
if [ "${__KEYS["${ENTRY}"]-0}" -eq 0 ]; then | |
if [ "${#__KEYS[@]}" -gt 0 ]; then | |
__VALUE="${__VALUE}:${ENTRY}" | |
else | |
__VALUE="${ENTRY}" | |
fi | |
__KEYS["${ENTRY}"]=1 | |
fi | |
done | |
export "$1"="${__VALUE}" | |
} | |
fi | |
pathlist_cond_append() { | |
pathlist_has "$1" "$2" || pathlist_append "$1" "$2" | |
} | |
pathlist_cond_prepend() { | |
pathlist_has "$1" "$2" || pathlist_prepend "$1" "$2" | |
} | |
pathlist_head() { | |
pathlist_remove "$1" "$2" | |
pathlist_prepend "$1" "$2" | |
} | |
pathlist_cond_head() { | |
pathlist_has "$1" "$2" && pathlist_head "$1" "$2" | |
} | |
pathlist_tail() { | |
pathlist_remove "$1" "$2" | |
pathlist_append "$1" "$2" | |
} | |
pathlist_cond_tail() { | |
pathlist_has "$1" "$2" && pathlist_tail "$1" "$2" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment