Skip to content

Instantly share code, notes, and snippets.

@alganet
Created August 19, 2022 16:57
Show Gist options
  • Save alganet/34197f3e5c08eeb287f25ccd3882fc0f to your computer and use it in GitHub Desktop.
Save alganet/34197f3e5c08eeb287f25ccd3882fc0f to your computer and use it in GitHub Desktop.
Portable shell boilerplate
#!/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