Date: Fri, 13 Oct 2023 14:21:59 -0400 From: "Dale R. Worley" <wor...@alum.mit.edu> Message-ID: <87bkd2idrs....@hobgoblin.ariadne.com>
| but I coded an instance of | your description (above), and it does not show the dubious behavior that | you report. Your test isn't accomplishing what is desired I believe. I can't speak directly to what is happening with bash, as I don't look at its source code (absurd GNU licensing nonsense prevents it) but I believe we have a similar problem in the NetBSD shell (but without the wrinkle added by bash's "novel" interpretation of what unset should mean) for which I have been designing a fix over the past week or two (not inspired in any way by this issue in bash, I've been working on it, and pondering it earlier, longer than that). The issue we have (which possibly might be similar in bash, but only possibly - but it would explain the symptoms) is that when one does VAR=value command "VAR" is essentially made a local variable for command, so its value in the outlying environment is unchanged by the assignment of value. When command is an external command (something from the filesystem) this all works just fine, and there are no issues, command is run, the local variable is removed, and the previous global remains intact. But when the command is a function, or a shell builtin (or the '.' command, which is almost both of those) then we have some strange effects. Consider the following code in command (which can be a function, or a file executed via '.' (or in bash, source)) echo $VAR VAR=foo echo $VAR now that should (and is almost certain to) print "value" and then "foo". When command is finished, VAR will be back to being whatever it was before command was executed, because of the nature of it being considered local. But that's wrong, all "VAR=foo command" is supposed to do, is to put VAR into the environment of command, without altering it in the shell environment that is executing command. If command is a function, or a '.' script (or a shell builtin, which was the context in which I first considered this issue) which alters VAR, the global VAR should be altered - that it was initialised in command from its environment should be irrelevant (this is why external commands have no issues, they have no way to even attempt to alter the values of variables in the calling shell). Now in bash, this get weirder, because of its strange interpretation of what "unset" should do to a local variable (assuming that this is what is happening in bash as well, and this is just a guess) when the variable wasn't declared local inside the function which does the unset (but somewhere else - which is the case here, in fact, there is no function at all). That would be why adding the "unset OUTSIDE" "fixes" things, you're using a very quirky bash trait to work around a bigger problem - that unset removes the local variable, and gives you access to the global again, which is what you wanted. (If that "unset" worked properly, and simply marked the local variable as being unset, then it wouldn't help to fix things at all). I suspect that a simpler fix might be to change OUTSIDE=clone . inner into OUTSIDE=clone . inner The former is semi undefined (at best) as to its effect according to POSIX, and certainly overkill for what you're doing, since you are actually wanting to operate on a global variable, and inner is going to change its value, worrying about what it is, or rather would be, in the outer script, after the ". inner" command, if inner did not alter OUTSIDE is kind of unnecessary. In this variant, there is nothing even smelling like a local variable, just the global OUTSIDE, which will get updated however that happens, when inner finishes, whatever it left in OUTSIDE will be what the outer script sees, no attempt to restore what the outer script used to have is required. I'll leave it to Chet, or perhaps one of the others here who do understand bash internals to confirm whether this is a likely explanation for the issue, or at least an approximation of ot. If it is, it is non-trivial, but I believe possible, to fix. But note I'm not finished with fixing my version of this problem yet, so I really cannot yet be certain about this. kre