Re: Issue with VAR=foo cmd where VAR is a named reference
Philippe Altherr <[email protected]>
| Newsgroups | gmane.comp.shells.zsh.devel |
|---|---|
| Message-ID | <CAGdYchsM9JbZT4W9qdGSB7eT6X-=WiCj1wmd_ynb=m9uSys5Hw@mail.gmail.com> |
>
> Hmm, there's a complication here where you have to consider that (per
> POSIX) some builtin commands preserve assignment to prefix environment
> strings and some do not. I don't immediately recall which category
> "typeset" falls into.
>
I didn't know about that but the code to save and restore the assigned
parameters is indeed conditional
<https://github.com/zsh-users/zsh/blob/134338255ee2689b4498118ded987c11324fcc9f/Src/exec.c#L4061-L4080>.
If POSIXBUILTINS is enabled, typeset preserves the assignments:
% setopt POSIXBUILTINS; var=foo; var=bar typeset -p var; typeset -p var
typeset var=bar
typeset var=bar
> Exporting named references is in principle possible
>
> I think that would be a bad choice. For security reasons it should
> not be possible to import a named reference, and other programs would
> have no idea what to do with an environment instrumented by zsh for
> the purpose.
>
I don't mean that it should be possible to export named references as
something special that would be recognized as a named reference by a Zsh
shell. I just mean that tagging a named reference R with -x could have for
effect to augment the environment with the key value pair R=$R (if R refers
to a non-array variable):
% typeset var=foo
% typeset -nx ref=var
% printenv | grep ref=
ref=var
% zsh -c 'typeset -p ref'
export ref=var
In principle, this is trivial. In practice, it's difficult because the
environment is precomputed. Each time an exported scalar is updated, its
associated key value pair is updated in the precomputed environment. For
exported named references, you would have to go through the whole parameter
table each time a scalar is updated just to find whether there are exported
named references that refer to it and update their associated key value
pairs in the precomputed environment. That would be prohibitively expensive.
> In other words, VAR=foo cmd, runs cmd with a parameter table where VAR's
> value has been temporarily changed to foo. If VAR happens to be a named
> reference, then it's the value of its referred variable that is changed.
>
> I'm undecided about that. It could be argued that
> VAR=foo command
> should behave like
> () { local -x VAR=foo; command }
> That is, VAR in the environment is entirely distinct from VAR in the
> calling shell. The difficult exception is the builtins that are
> supposed to preserve assignment. I suppose ksh behavior would be
> worthwhile to investigate.
>
That's not unreasonable and it would make things pretty simple but I fear
that it's not compatible with the current implementations; chances are that
it would break existing scripts. Here is what the current implementation
more or less does for VAR=foo cmd:
# Save the state of the variable referred by VAR
typeset -x VAR # For named references, the -x applies to the referred
variable
VAR=foo
cmd
# Restore the state of the variable referred by VAR
One difficulty (to switch to your proposal) is that the current
implementation preserves the type of the variable. The following exports
the value "7", not "3+4" (ksh does the same):
% typeset -i VAR=2; VAR=3+4 printenv VAR; typeset -p VAR
7
typeset -i VAR=2
Another difficulty is that assignments can use += (this too works the same
in ksh)
% typeset -i VAR=2; VAR+=3 printenv VAR; typeset -p VAR
5
typeset -i VAR=2
It's even possible to assign slices
% fun() { typeset -p VAR }; typeset VAR=1234567; VAR[2,6]=abc fun; typeset
-p VAR
typeset -g VAR=1abc7
typeset VAR=1abc7
But strangely that only works for functions and builtins and here the
variable isn't restored to its previous state.
I have personally written scripts that rely on the fact that -i is
preserved and that += works. Switching to the equivalent of a local
variable would break these. No big deal for me but chances are that other
people also made use of these features.
If we keep the current implementation, then it's pretty much unavoidable
that REF=foo cmd updates the referred variable. We can just avoid exporting
the referred variable.
Philippe