Created
August 19, 2022 16:57
-
-
Save alganet/34197f3e5c08eeb287f25ccd3882fc0f to your computer and use it in GitHub Desktop.
Portable shell boilerplate
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
#!/usr/bin/env sh | |
# Backup of a draft with support for many shells: | |
# bash, dash, zsh, posh, yash, ksh, mksh, oksh, busybox and so on. | |
# | |
# I tested every single one of them. | |
# | |
# Boilerplate doesn't do much. It normalizes local vars, and exposes | |
# basic functions: | |
# | |
# _sh_has - checks whether a builtin exists | |
# _sh_fn_declaration - prints a function declaration compatible with the | |
# runtime shell | |
# _sh_printe - Prints escaping chars, equivalent to printf %b | |
# _sh_print - Prints raw strings, equivalent to printf %s | |
# _sh_walk_pathlist - The code runs on PATH=, so if you want | |
# to exec an external program, you need to walk | |
# is manually. It is faster than using command -v | |
# inside a subshell (no forks!) | |
# | |
# You should only use this if you are aiming to support multiple | |
# shell interpreters. | |
# | |
__pat__="${PATH:-".:"}" | |
__ops__="${-:-"-"}" | |
__eol__=' | |
' | |
IFS=" " | |
PATH="" | |
set -euf | |
_sh_has () { | |
command -v $1 >/dev/null 2>&1 | |
} | |
if _sh_has command | |
then | |
_sh_has local || alias local=typeset | |
! _sh_has setopt || setopt sh_word_split | |
! _sh_has shopt || set -o posix | |
fi | |
############################################################################## | |
_main () { | |
: | |
} | |
############################################################################## | |
_sh_walk_pathlist () { | |
local call="$1" | |
shift | |
IFS=":" ; set -- $1 ; IFS=" " | |
while test $# -gt 0 | |
do $call "$1" && shift || return 0 | |
done | |
return 1 | |
} | |
if eval "_hasleak(){ local _hasleak=:;};_hasleak;\${_hasleak:-false}" | |
then | |
unset -f _hasleak | |
_fnlist=$(typeset +f) | |
IFS="$__eol__" | |
for _declaration in $_fnlist | |
do | |
_name=${_declaration%"()"} | |
_code="$(typeset -f $_name)" | |
eval "function $_name ${_code#"$_declaration"}" | |
case $__ops__ in *x*) typeset -ft $_name;; esac | |
done | |
IFS=" " | |
unset _fnlist _declaration _name _code _hasleak | |
_sh_fn_declaration () { REPLY="function $1"; } | |
else | |
_sh_fn_declaration () { REPLY="$1 ()"; } | |
fi | |
if _sh_has printf | |
then | |
_sh_printe () { printf %b "$1"; } | |
_sh_print () { printf %s "$1"; } | |
elif _sh_has print | |
then | |
_sh_printe () { print -n "$1"; } | |
_sh_print () { print -ln "$1"; } | |
else | |
REPLY="$(echo -n \\061)" | |
case "$REPLY" in | |
'1') | |
_sh_printe () { echo -n "$1"; } | |
_sh_print () { | |
IFS='\' ; set -- $1 ; IFS=' ' | |
echo -n "$1" && shift | |
while test $# -gt 0 | |
do echo -n "\\\\$1" && shift | |
done | |
} | |
;; | |
esac | |
REPLY= | |
fi | |
_main "${@:-}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment