Date: Wed, 11 Aug 2021 15:31:08 -0400 From: Chet Ramey <chet.ra...@case.edu> Message-ID: <87b7cb49-444f-aa06-198d-57f4071a0...@case.edu>
| I believe I'd rather have variables behave as they're documented. It's more | predictable. I'm not sure I follow the logic that leads to that conclusion - variables that simply ignore being set isn't what I'd call predictable. Ones where setting them has some effect (aside from storing the value) are understandable, but (aside from read only vars, where an attempt to set is an error) vars that don't allow writing are just something very odd. | Bash allows variables in the environment to override special | variables -- for example, UID and EUID -- I didn't know that, but that makes things even more confusing. | and I've gotten bug reports about that behavior for forever. That's probably because it is unpredicable and weird - either an attempt to set the var is ignored (or the var is read only and it is an error) or they're allowed, possibly with the effect of removing any special properties the variable has. Works from the environment but not in the script makes no sense to me at all. Is this documented anywhere (in the man page)? It certainly isn't in the section where each var is described, and we're told that attempts to set the var are ignored. Incidentally, while I was scanning (not really reading) the man page to see if I could find anywhere this is documented (I didn't, but that doesn't mean it isn't there) I noticed that in the section on the environment (section heading "ENVIRONMENT") it mentions how the environment for an executed command is formed, which is all fine as far as it goes, but it omits any mention of "set -a" which probably would be worth including there in some form or other. [This paragraph has nothing whatever to do with the rest of this thread...] | That's one of the problems here: the author never intended this script to | run in any shell other that Debian's dash. That is possible perhaps, I don't know the author, or the script, but being able to run on dash (which is a fairly minimalist POSIX compat sh) generally means being able to run on any POSIX compat sh, we (people who modify shells) generally expend much effort in trying to make sure that the extensions we make to the shell don't break scripts written by people who have no idea that the extension exists. | If they had, maybe they would have tested it on other shells, Perhaps they did, I have no idea, without looking at it, I'm guessing that if it worked in dash it would also work in other (modern) ash derived shells, and probably bosh and yash, and most probably mksh as well. It's hard to tell about zsh and ksh93 as they have so many extensions and variations. | The other problem is the OP assuming that posix mode would change it, when | posix mode means something else. Sure, I agree with you there, there's no reason for posix mode to make any difference to this. I'm not sure he assumed it would change it quite so much as hoped that it might (from my reading of what was said.) | It could have, but I'm not seeing a good enough reason to change it | 25-30 years in. Not the ability to run more scripts that simply run everywhere else? And given that changing it is benign to existing scripts that make use of these vars (and completely irrelevant to those that don't). That's even more true than I thought it might be now I know of the way these things work when in the environment - though because of that (and because with it, it is trivially possible to subvert scripts which use any of these vars simply by loading the environ with lots of junk) it gets a bit more important to provide a way for a script to be sure it is getting the enhanced version of a variable - scripts that know they want to use GROUPS or UID (etc) in the way bash defines them can easily include a command to make sure that always works - in the NetBSD sh, if we had these vars, which we don't their description would be something like we have for EUSER and SECONDS (which we do have)... EUSER Set to the login name of the effective user id running the shell, as returned by getpwuid(geteuid())->pw_name (See getpwuid(3) and geteuid(2) for more details.) This is obtained each time EUSER is expanded, so changes to the shell's execution identity cause updates without further action. If unset, it returns nothing. If set it loses its special properties, and is simply a variable. See the specialvar built-in command for remedial action. SECONDS Returns the number of seconds since the current shell was started. If unset, it remains unset, and returns nothing, unless set again. If set, it loses its special properties, and becomes a normal variable. See the specialvar built-in command for remedial action. (there's also HOSTNAME which is just the same). Like any other var, these can be set in the script, in the environment, or in a startup file (or any other .'d file). A script that intends to use them is expected to do something like if ! specialvar EUSER SECONDS then help! fi Assuming we don't call for help, after that has executed, both EUSER and SECONDS will be magic, whatever was in the environment or startup files (what happens after that is entirely governed by what the script does). (If the script desires to know which var is missing from the shell, in case we do call for help, it needs to test/enable them one at a time.) specialvar variable ... For each variable name given, if the variable named is one which, in this sh, could be treated as a special variable, then cause that variable to be made special, undoing any effects of an earlier unset or assignment to the variable. If all variables given are recognized special variables in this sh the specialvar command will exit with status 0, otherwise 1. Invalid usage will result in an exit status of 2. Note that all variables capable of being special are created that way, this command is not required to cause that to happen. However should such a variable be imported from the environment, that will cause (for those special variables so designated) the special effects for that variable to be lost. Consequently, as the contents of the environment cannot be controlled, any script which desires to make use of the properties of most of the special variables should use this command, naming the variables required, to ensure that their special properties are available. The "for those special variables so designated" is because there are some (like RANDOM and LINENO) which are more magic, and where the special properties can never be removed (though they can be hidden if the variable is unset, but setting it again resumes the magic variable (for RANDOM with a new seed - as given if a numeric value was assigned, or from a kernel random number source otherwise). These are very rare, and only for var names known to be special in many shells (LINENO is in POSIX so should be in every shell, though the effects of unsetting or setting it aren't specified there, rather than don't do that...) (Of course, just like bash, we also have a bunch of vars, which are just vars, except they're initialised to something particular when the shell starts - some before environment processing, others after it (ie: the environment cannot control them ... PPID, another POSIX var, is one like that, though POSIX doesn't say anything about what happens if the sh finds PPID in the environment). | The original implementation was read-only, but that caused bug reports | because trying to unset a readonly variable is a fatal error in posix | mode. That would perhaps be better, at least then script writers would get an obvious error, rather that simply having assignments ignored, and then "wrong" values produced upon expansion. Much safer - but even better is to leave them writeable, but turn the magic off if written. kre