-1

I have a bash function declared like so:

function foo {
  echo "this is foo";
}

I didn't call export -f foo, but it still was available in subshells.

However, typically when I declare a function like this instead:

foo(){
  echo "this is foo";
}

then I have to call:

export -f foo;

am I imagining things, are is there a difference in export behavior in the different declaration syntax?

Note that I didn't need to export the functions as far as I can tell when I just did:

. my_script_with_foo_in_it.sh  # this is in ~/.bash_profile/.bashrc

then later in a bash shell I could call:

foo

without any issue, even without exporting the function.

muru
  • 72,889
  • 1
    Subshells? Or scripts executed in a new shell? Can you provide a minimal example of this behaviour? – muru Jun 25 '18 at 04:54
  • 2
  • AFAICT, both bash -c 'foo() { echo bar; }; (foo)' and bash -c 'function foo { echo bar; }; (foo)' work fine, and the linked question's answers do not mention any difference related to export behaviour. (And neither bash -c 'function foo { echo bar; }; bash -c foo' nor bash -c 'foo() { echo bar; }; bash -c foo' work: both fail with foo not being found.) – muru Jun 25 '18 at 05:04
  • @muru I guess not subshells - in my case the bash script would be sourced by the shell, and then the bash functions executed in the new shell (I guess that's not a subshell). – Alexander Mills Jun 25 '18 at 05:09
  • 1
    @AlexanderMills "in the new shell"? Is that new shell the same that sourced it? Can't you just show what you're doing? – Kusalananda Jun 25 '18 at 05:41
  • Thanks yeah I just updated the question to make it more clear – Alexander Mills Jun 25 '18 at 05:44

1 Answers1

3

When sourcing a script with either source or ., the contents of the script is executed in the current shell's environment. Any functions defined in the sourced script will be available in the current shell after sourcing, as well as any shell variables (without the need for exporting). This is the purpose of sourcing a script.

This is how a /etc/profile or /etc/bash.bashrc file is able to set up a basic environment for a interactive/login shell, for example.

Moreover, some commands are executed in a subshell environment that is a duplicate of the shell environment. In such an environment, shell variables and functions are available. See also the POSIX standard about Shell Execution Environment (my emphasis):

A subshell environment shall be created as a duplicate of the shell environment, except that signal traps that are not being ignored shall be set to the default action. Changes made to the subshell environment shall not affect the shell environment. Command substitution, commands that are grouped with parentheses, and asynchronous lists shall be executed in a subshell environment. Additionally, each command of a multi-command pipeline is in a subshell environment; as an extension, however, any or all commands in a pipeline may be executed in the current environment. All other commands shall be executed in the current shell environment.

Note that a subshell is different from a child process.

Exporting a variable is only needed to create an environment variable. Environment variables are inherited by any child process.


Also note that having a directory called ~/.bash_profile is a bit confusing, as a bash shell will try to source the regular file ~/.bash_profile when starting a login shell. I suggest that you rename your ~/.bash_profile directory into something like ~/.shell or ~/.shell_startup if you want to move your shell initialization files elsewhere. These file would still have to be called from ~/.bash_profile and ~/.bashrc if you wish them to be sourced automatically.

Kusalananda
  • 333,661
  • I have needed to export functions with export -f if I call the bash function from a subprocess / subshell, at least as far as I can tell. – Alexander Mills Jun 25 '18 at 06:01
  • 3
    @AlexanderMills You should only have needed to do that if you wanted to call the function from a child shell (e.g. from within bash -c '...'). Functions will be available in subshells (inside (...) for example). – Kusalananda Jun 25 '18 at 06:02
  • Yes I think that's what it was, I am certain of it. It wasn't working, then I exported the function and it worked. – Alexander Mills Jun 25 '18 at 06:05