[Gllug] bash indirect variable referencing ugliness
Nix
nix at esperi.org.uk
Fri Nov 24 00:55:54 UTC 2006
On 21 Nov 2006, Tethys said:
> Errr... yes. Just get rid of them all. They're not necessary:
>
> adapter="adapter_$service"
> lnb="lnb_$service"
> szapout="szapout_$service"
> pid="pid_$service"
> ip="ip_$service"
>
> echo "Config values for service $service:"
> for value in adapter lnb_settings szapout pid ip
> do
> varname="${value}_$service"
> echo " $value: ${!varname}"
> done
Bah, far too sane.
I present something in ksh (probably working on any POSIX shell) which
does the same thing with knobs on and should really *really* not be
applied to untrusted data:
#
# expand_variable VARIABLE
#
# Expand a VARIABLE by repeatedly evaluating it until it is entirely
# expanded. This handles variables that point to other variables,
# variables whose names are composed of the values of one or many other
# variables, and so forth. It is not fast, but it is flexible.
# This permits the use of variable constructs like ${FOO_${BAR}_BAZ},
# which are otherwise illegal in POSIX shells.
#
# This is fairly slow.
expand_variable()
{
# All variable names start with an underscore; because we are expanding
# the caller's variables here we do not want our own variable names to
# collide with the caller's.
typeset _VARIABLE="$1"
while :; do
# Multiple sets of variables in succession confuse the nested expander's
# regexps, and cannot be dealt with in there, as picking out distinct
# levels of variables requires matching brackets, and this cannot be
# done by regular expressions. So we pull the start off the variable,
# and if we need to, we recursively expand the end of the variable until
# only a starting piece is left. So `${FOO${BAR}}${BAR${BAZ}}quux' is
# cut into two pieces, and `${BAR${BAZ}}quux' is handled by a recursive
# call.
# First, cut the variable into starting and ending pieces, with a simple
# awk bracket matcher, modified to give everything if no braces are
# present at all.
typeset _VPBEGIN=`echo $_VARIABLE |\
awk '
{
braces=0;
if ((i=index($0,"{"))==0) {
print $0;
}
do {
if (substr ($0,i,1)=="{") {
braces++;
} else if (substr ($0,i,1)=="}") {
braces--;
}
++i;
} while (i<=length ($0) && braces!=0);
print substr($0,1,i-1);
}'`
typeset _VPEND=`echo $_VARIABLE | sed "s/^$_VPBEGIN//"`
# If the ending piece has any variable expansions in it, expand them.
(echo "$_VPEND" | grep -F '${' > /dev/null 2>&1) && \
_VARIABLE="$_VPBEGIN"`expand_variable "$_VPEND"`
# Handle nested and other expansion, and the base case.
case $_VARIABLE in
# Nested expansion. Cut the variable name up and expand the middle bit.
# This set of regular expressions should perhaps win some kind of award
# for unreadability; matching ${} constructions is not pretty.
*\${*\${*}*}*)
typeset _VPBEGIN=`echo $_VARIABLE | sed 's/\(^[^\$]*\${[^\$]*\).*$/\1/'`
typeset _VPMIDDLE=`echo $_VARIABLE | sed 's/^[^\$]*\${[^\$]*\(\${.*}\)[^}]*}[^}]*$/\1/'`
typeset _VPEND=`echo $_VARIABLE | sed 's/^.*}\([^}]*}[^}]*\)$/\1/'`
_VARIABLE="$_VPBEGIN"`expand_variable "$_VPMIDDLE"`"$_VPEND";;
# Conventional expansion.
*\$*) _VARIABLE=`eval echo $_VARIABLE`;;
# Expansions completed.
*) break;;
esac
done
echo "$_VARIABLE"
}
--
`The main high-level difference between Emacs and (say) UNIX, Windows,
or BeOS... is that Emacs boots quicker.' --- PdS
-------------- next part --------------
--
Gllug mailing list - Gllug at gllug.org.uk
http://lists.gllug.org.uk/mailman/listinfo/gllug
More information about the GLLUG
mailing list