Skip to content

Instantly share code, notes, and snippets.

@jimklimov
Forked from bk2204/local.sh
Created April 4, 2018 13:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jimklimov/e9bf4e99ca5129fd1810e292508ef6e0 to your computer and use it in GitHub Desktop.
Save jimklimov/e9bf4e99ca5129fd1810e292508ef6e0 to your computer and use it in GitHub Desktop.
Reasonably portable technique for local variables in shell scripts
#!/bin/sh -e
# This shell script demonstrates how to use the local keyword to create
# dynamically-scoped variables in various shells. Notably, this technique works
# with AT&T ksh, as well as bash, dash, mksh, pdksh, zsh, busybox sh, and other
# Debian Policy-compliant sh implementations.
# Simple Perl-compatible testing framework. Produces TAP output.
COUNT=0
is () {
COUNT=$(($COUNT + 1))
if [ "$1" = "$2" ]
then
printf 'ok %d\n' $COUNT
else
printf 'not ok %d\n' $COUNT
fi
}
finish () {
printf '1..%d\n' $COUNT
}
trap finish EXIT
# True if this is AT&T ksh, but not MirBSD ksh or pdksh.
is_att_ksh () {
[ -n "$KSH_VERSION" ] && [ -z "${KSH_VERSION##*Version AJM*}" ]
}
is_att_ksh && alias \local=typeset
# A helper to declare a function. We declare our actual code in a function
# starting with an underscore (e.g. _f). We then use this helper to create a
# wrapper (e.g. f) around that. With AT&T ksh, this uses the ksh-style function
# syntax to create the scoping that's required for the local (typeset) to work
# properly. The local variables are technically scoped to f, not _f, but that
# doesn't practically matter.
#
# For bash, dash, mksh, pdksh, busybox sh, and anything else, we use the
# standard POSIX syntax to call the underlying function. This is more portable.
decl () {
if is_att_ksh
then
eval "function $1 { _$1 \"\$@\"; }"
else
eval "$1 () { _$1 \"\$@\"; }"
fi
}
# To actually declare a function, we first declare the actual function with an
# underscore in front of it…
_f () {
local a
a="$1"
is "$a" 2
}
# …and then we use the decl helper to create the wrapper function.
decl f
# A simple test that the local keyword does indeed work in the shell in
# question.
a=1
is "$a" 1
f 2
is "$a" 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment