Created
October 31, 2016 23:45
-
-
Save bk2204/9dd24df0e4499a02a300578ebdca4728 to your computer and use it in GitHub Desktop.
Reasonably portable technique for local variables in shell scripts
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 -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