In Posix mode, Bash exports functions as well as variables when `set -o
allexport` (`set -a`) is in effect.

$ set -o posix -o allexport
$ foo() { echo Bar; }
$ declare -pF foo
declare -fx foo
$ echo $BASH_VERSION
5.3.0(8)-maint

This behaviour does not appear to match Posix' description of `set` in issue
8 (§2.15)
<https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html#tag_19_26>
(*1),
which mentions *variable assignments* (and notes that certain implicit or
indirect assignments are included) but mentions neither *functions* nor any
term that could be construed as including them.

Brief tests of ksh & zsh (*2) indicate that those shells do not exhibit
this behaviour; rather, ‘set -a’ causes them to export only variables,
regardless of emulation/compatibility settings, in line with the Posix
description.

Bash's man & info pages describe this behaviour thus:
‘-a’
    Each variable or function that is created or modified is given
    the export attribute and marked for export to the environment
    of subsequent commands.

…so I guess this could be construed as a Bash extension to the standard.

However `help set` does *not* mention functions:
-a  Mark variables which are modified or created for export.

Anyway, it seems to me that exporting functions when in Posix mode could be
construed as a bug.

Maybe exporting functions as a result of `allexport` should be disabled
when in Posix mode, and documented as an extension otherwise? Does that
seem reasonable?

(Personally I would go further, given the pain I've seen caused by
inadvertently imported functions,(*3) but I expect opinions will differ.)

Relatedly, does it make sense for a variable to have both the ‘nameref’ and
‘exported‘ attributes?
(If that might change in the future, then perhaps there should also be a
deprecation notice to the effect of “A future version of Bash may also
limit which variables are exported” (when `set -a` is in effect).(*4))

-Martin

PS:

Chet, do you remember why this extension was implemented? Was it a case of
mimicking some other shell, or based on something else? A quick hunt
through the git history shows that `bind_function` has included a check for
`mark_modified_vars` since before the git history started at Bash-v1.14.7.
(*5)


Footnotes:
(*1: substantively unchanged from previous issue 7 (§2.14)
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_25>,
and issue 6 (§2.14)
<https://pubs.opengroup.org/onlinepubs/009695399/utilities/set.html>)

(*2: at least, mine don't when I test them:
· ksh --version says “sh (AT&T Research) 93u+m/1.0.4 2022-10-22”;
· zsh --version says “zsh 5.9 (x86_64-debian-linux-gnu)”.)

(*3: Shellshock was only the most visible problem; it can still cause very
wierd hard-to-debug problems. I would personally like to deprecate the
application of allexport to functions, even in non-Posix mode, with a
notice along the lines of: “Unless in Posix mode, new functions are
*also* automatically
exported when `allexport` is in effect; however this is a non-standard
extension that may change in a future version of Bash.” I wouldn't go as
far as entirely removing it, since someone will doubtless have a use for
it, but perhaps there could be separate `set -o allexport` and `set -o
allfuncexport` options? If this is going to happen, then I think it would
be preferable to introduce the latter option before changing the behaviour
of the former, so that people can adapt their scripts before it's removed.)

(*4: In the event that ksh-style `namespace` gets implemented, I would
strongly prefer that most variables in most namespaces not be exportable,
in which case `allexport` wouldn't affect them. In particular, I suggest
that the equivalents of “export .sh.bashcompatlevel” and “export
.lexicalscope.myvar” should fail.)

(*5:
$ *git blame devel variables.c | grep -A3 att_function | grep -A1 *
*mark_modified_vars*
7117c2d221 (Jari Aalto 2002-07-17 14:10:11 +0000 3480)   if
(mark_modified_vars)
7117c2d221 (Jari Aalto 2002-07-17 14:10:11 +0000 3481)     VSETATTR (entry,
att_exported);
$ *git blame 7117c2d221^ variables.c | grep -A3 att_function** | grep -A1 *
*mark_modified_vars*
^726f63884 (Jari Aalto 1996-08-26 18:22:31 +0000 2026)   if
(mark_modified_vars)
bb70624e96 (Jari Aalto 2000-03-17 21:46:59 +0000 2027)     VSETATTR (entry,
att_exported);
*$ git blame bb70624e96^ variables.c | grep -A3 att_function** | grep -A1 *
*mark_modified_vars*
^726f63884 (Jari Aalto 1996-08-26 18:22:31 +0000 1932)   if
(mark_modified_vars)
^726f63884 (Jari Aalto 1996-08-26 18:22:31 +0000 1933)
entry->attributes |= att_exported;
)

Reply via email to