[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: declare a="$b" if $a previously set as array

From: Stephane Chazelas
Subject: Re: declare a="$b" if $a previously set as array
Date: Tue, 9 Dec 2014 10:59:14 +0000
User-agent: Mutt/1.5.21 (2010-09-15)

Thanks konsolebox and Eduardo, glad to see I'm not the only one
seeing an issue in that.

A few additions inline:

2014-12-09 10:51:51 +0800, konsolebox:
> (But I think those who used to recommend using declare as a general tool
> for assigning values remotely over evil eval would love it since
> it makes assignments like `declare -g "$var=$something"` possible
> which naturally should have been illegal.)

BTW, it's worth noting (and maybe documenting) that word
splitting and filename generation are performed in:

declare -g $var=$something
(or declare ''var=$something or declare f\oo=$bar...)

So it must be indeed:

declare -g "$var=$something"

> Anyhow, this problem would only happen if a variable in a specific
> scope (and only in that scope) has already been set previously as an
> array and it doesn't always happen if you write your scripts well.
> > It may be worth recommending people do a "unset var" before
> > doing a "declare [-<option>] var"
> I actually find it better to mention that on a simple assignment like
> declare var=$something, var's type doesn't change if it has already been
> declared previously as an array.

Strictly speaking,

"if it has already been declared" *or assigned* (as in a[0]=x or
a=()) "previously as an array" *in the current scope*,
otherwise, the variable is declared as a scalar (but see below
for more complications), :

$ bash -c 'f() { declare a=1; declare -p a; }; a=(); f'
declare -- a="1"

However, if "a" was exported or readonly even in an outer scope
before, it's still exported or readonly (that doesn't seem to be
the case for any of the other variable attributes):

$ a=3 bash -c 'f() { declare a=1; declare -p a; }; a=(); f'
declare -x a="1"
$ a=3 bash -c 'f() { declare a=1; declare -p a; }; declare -r a=2; f'
bash: line 0: declare: a: readonly variable
declare -rx a="2"

What that means is the "local" or "declare" is not a complete
solution to your scoping problem. You still need to resolve to
name spaces. See the eternal discussion between ksh and bash
about dynamic vs static scope for local variables as well.


$ a=3 ksh -c 'function f { typeset a=1; echo "$a"; env | grep "^a"; }; typeset 
-r a=2; f'

("a" in the function is not exported but the original "a" was
removed from the environment, not sure it's a lot better, but
it's probably as good as we can reasonably get without major
change of design).

$ a=0 ksh -c 'function f { typeset a=1; g; h; echo "f: $a"; }; function g { 
a=2; }; function h { typeset a=3; };f'
f: 1

"f" doesn't have to worry about alien functions changing its
local variables under its feet.

> Shared functions otoh should be responsible of making sure that their
> work variables are placed as local.  This is also a common
> practice.

That doesn't apply if you want to use a function library written
in "sh" (the POSIX "sh" language doesn't have local scope except
via subshells).

Then again, that library should use its own namespace.

So, if good practice is followed all over the board, then that
issue is very unlikely to be hit.

Then again, I see no compelling reason not to fix it. Again, the
issue is aggravated by the fact that it's hard to detect (your
scripts will still work but will have a hidden vulnerability).


reply via email to

[Prev in Thread] Current Thread [Next in Thread]