9

The shellshock bug in bash works by way of environment variables. Honestly I was suprised by the fact that there is such a feature like:

"passing on of function definitions via env vars"

Therefore this question while maybe not perfectly formulated is to ask for an example or a case in which it would be necessary to have this feature?

Bonus. Do other shells zsh, dash etc. also have this feature?

  • It uses the env vars to pass on function definitions. What do you mean with "Why does it not simply keep the environment variables available/accessible?" ? – Anthon Sep 27 '14 at 11:48
  • @Anthon Thanks for the comment. Maybe I should be clearer and rephrase to. For what reason is it necessary to be able to pass on function definitions via env vars? – humanityANDpeace Sep 27 '14 at 11:51
  • 1
    I'm not 100% sure but I think that that e.g. is the way that GNU parallel get function definitions distributed if it invokes multiple bash instances. If not in that way it would have to write those in a file, that each invoked instance reads in and then you have to deal with problems like when that file can be removed. – Anthon Sep 27 '14 at 12:01
  • 2
    this thread has some history to it. exported functions, though, are insane. if you want a new shell to inherit old shell executable commands you .dot source the same file the old shell did. thats how its done - and that makes sense - or you feed the new shell the file as input when execing. once its read in once the file is cached by the kernel anyway. – mikeserv Sep 27 '14 at 14:59
  • @mikeserv Do I understand it right, that a big part of the shellshock is related to this feature which is not that much essential anyways? – humanityANDpeace Sep 28 '14 at 17:32
4

When a script invokes another script, variables of the parent script can be exported, and then they'll be visible in the child script. Exporting functions is an obvious generalization: export the function from the parent, make it visible in the child.

The environment is the only convenient way a process can pass arbitrary data to its children. The data has to be marshalled into strings that don't contain null bytes, which isn't a difficulty for shell functions. There are other potential methods, such as shared memory blocks or temporary files passed via file descriptors, but these could cause problems with intermediate programs that don't know what to do with them or would close them. Programs expect to run in an environment that contains variables that they don't know or care about, so they won't go overwriting or erasing them.

The choice of using the function name as the name of the environment variable is a strange one. For one thing, it means that an exported variable clashes with an exported function of the same name.

Exported functions are an old feature. Functions were added in the Bourne shell in SVR2, and exported functions in the Version 8 shell released the same year (1984). In that shell, variables and functions used the same namespace. I don't know how function export worked. The Heirloom shell is based on a Bourne variant which has functions but doesn't export them.

ATT ksh supposedly supports exporting functions, but looking at the source or playing with it, I can't see that it does, as of ksh93u.

env -i /usr/bin/ksh -c 'f=variable; f () { echo function; }; typeset -fx f; /usr/bin/env; ksh -c f'
_=*25182*/usr/bin/env
PWD=/home/gilles
SHLVL=1
A__z="*SHLVL
ksh: f: not found

Ksh's public domain clones (pdksh, mksh), dash and zsh don't support exporting functions.

  • 1
    thank you! So, without exporting functions feature functionality is lost, yet there are some shell like dash, zsh and pdksh etc. which lack this funcitonality, do I read this right? – humanityANDpeace Sep 28 '14 at 17:29
  • But when I export a function in bash, it goes into a variable like BASH_FUNC_f%%=() { echo hi }. Why would bash parse other environment variables? Why would it even parse BASH_FUNC_g%% when I am only calling f? (Apparently, pre-shellshock, the environment variable was just called f or g - but I'm still wondering why g would have been parsed if I don't ever call g in my script) – Metamorphic Aug 29 '18 at 5:38
  • @Met It has to look at all environment variables to figure out which ones are function definitions. It could memorize that fact and avoid parsing a function's code until the first time it's needed, but that would be additional complexity for very little gain. It's easier to have just one type of function and not two ("normal function" and "function from an environment variable that needs a bit of parsing"). – Gilles Aug 29 '18 at 5:47
  • Not clear. I'm suggesting that the obvious thing to do would have been, when I run something called f, (1) check for a shell function called f, (2) check for an environment variable called f, and try to parse it, (3) check each PATH component for an executable called f. How could parsing every environment variable as shell code, at shell startup, seem like a less complicated design? – Metamorphic Aug 29 '18 at 6:13
  • @Metamorphic You're suggesting to add another step that must be peformed on every command. You'd also have to add another step when defining or undefining functions (after unset -f foo, bash mustn't look for a function definition for foo in the environment anymore), when listing functions (how do you handle declare -f other than reading all the environment variables?), and whatever else I'm not thinking of. Your design only seems easier because you left out most of it. In contrast, doing everything at startup is a single piece of code and after that everything just works. – Gilles Aug 29 '18 at 6:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.