Date: Tue, 10 Aug 2021 10:22:29 -0400 From: Chet Ramey <chet.ra...@case.edu> Message-ID: <731876fc-39c0-4388-0c9e-bf560921b...@case.edu>
| In this case, you are using features outside what POSIX specifies. Using a variable name that's outside what POSIX specifies is hardly using a feature that's outside POSIX - if it were then there would be no safe non-trivial scripts, since any variable name might be made magic by some shell or other (and no, there's nothing special about all upper case variable names). Only those defined by POSIX to have some special meaning mean something, and even those can be re-used for another purpose as long as one doesn't expect the special behaviour to function correctly. That is, it is perfectly OK to write for IFS in 1 2 3 4 5 6 do command "${IFS}" IFS=$(( IFS % 3 )) if [ "$IFS" -eq 0 ] then othercommand "${IFS}" fi done as long as there's nothing in there which attempts to use field splitting (no "read" commands, etc, no unquoted variable expansions in arg lists, no use of $*) or that one actually wants the varying value of IFS to actually be the field separator. (One can use PATH, CDPATH, PWD, OLDPWD, OPTARG, OPTIND, HOME, PS1, ..., similarly, with similar restrictions on what is expected to work, or can be used ... doing "cd" will set PWD and OLDPWD, so you'd want to avoid that if using PWD or OLDPWD for some other purpose, and "pwd" is undefined if PWD has been altered, so you'd need to avoid that as well - similar restrictions for the others.) I found this when I attempted to make HOSTNAME special (not in bash) in a similar way to bash has (apparently) with GROUPS - scripts existed that used HOSTNAME as a variable, and expected that to work ... and that was entirely reasonable. (Nb: this is different than HOSTNAME in bash which is simply a var init'd to the name of the host at shell startup, my magic var tracks changes to the system's hostname and always returns the current hostname, ie: it executes gethostname(3) every time it is expanded). So, I changed things, and made almost every magic variable lose its magicness if the script (or the environment) assigns a value to the variable (or unsets it). That way scripts are free to use whatever variable names that they like (POSIX does not forbid them from doing so). (And if one wants a bash form of HOSTNAME variable, one can just do HOSTNAME=${HOSTNAME} ... the expansion happens when HOSTNAME is still magic, and gets the current hostname, the assignemnt saves that, and turns off the magicness). [Aside: I also added a "specialvar" built-in command, which takes a var name as an arg (or multiple, though that turns out to be less useful) and turns its specialness back on if it was off - and exits 0 if the var named (or all of them) are known special vars in the shell, or 1 if not. That way a script that wants to depend upon the specialness of HOSTNAME can do: if ! specialvar HOSTNAME; then abort "Need shell with HOSTNAME"; fi (where abort is presumed to be a function which does what is expected) and then after that, HOSTNAME will have its magic properties (whatever was its status previously) and everything else that simply wants it to be a variable can simply not do this, use HOSTNAME as a variable (after giving it a value however is desired - including inheriting it in the environemnt), and it will work just like "x" would work as a variable.] The exceptions to this are those very very few magic vars that need to be able to be given values in order to work as defined (like RANDOM, to set the seed) - that set of vars should be kept as limited as possible (and even those lose the magic if unset, until "specialvar" returns it). Note: there is no likely compat issue with changing this in bash, any var defined as "assignments are ignored" isn't going to be having values assigned to it in any rational script that depends upon its magic properties. That is, I cannot think of any reason GROUPS in bash, or any of the others defined similarly (except perhaps the BASH* vars) should not simply work as vars if used that way. I can think of even less reason for UID and EUID to be read only. kre ps: of course if the script doesn't mention or use a magic variable at all, it remains magic without need of "specialvar" but no-one knows or cares. The one slight oddity is that if one uses a variable without assigning a value to it, then if it happens to be one of the special ones, weird things can happen - but that's (kind of) true of anything, any variable might appear in the environment (not just upper case names), so it is never safe to assume that any var not set in the script will simply turn into "" if expanded. Uninit'd variables are as much a potential bug in scripts as they are in C (or other) programs.